Created
March 8, 2012 02:01
-
-
Save JulianR/1998017 to your computer and use it in GitHub Desktop.
Generic compound service
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class BatchClient | |
{ | |
private readonly CeyenneClient _client; | |
private List<object> _batch; | |
private CompoundResponse _response; | |
public BatchClient(CeyenneClient client) | |
{ | |
_client = client; | |
_batch = new List<object>(); | |
} | |
public void AddMessage(object message) | |
{ | |
_batch.Add(message); | |
} | |
public void SendBatch() | |
{ | |
var compound = new Compound | |
{ | |
Values = _batch.ToDictionary(k => k.GetType().Name, v => TypeSerializer.SerializeToString(v)) | |
}; | |
_response = _client.Send(compound); | |
} | |
public T Get<T>() | |
{ | |
if (_response == null) | |
{ | |
throw new InvalidOperationException("Batch has not been sent yet"); | |
} | |
string value; | |
if (!_response.Result.TryGetValue(typeof(T).Name, out value)) | |
{ | |
return default(T); | |
} | |
var result = TypeSerializer.DeserializeFromString<T>(value); | |
return result; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var client = new CeyenneClient("http://localhost/Services/servicestack"); | |
var batch = client.CreateBatch(); | |
batch.AddMessage(new GetUser | |
{ | |
ID = 1 | |
}); | |
batch.AddMessage(new GetStation | |
{ | |
ID = 1 | |
}); | |
batch.SendBatch(); | |
var result = batch.Get<GetUserResponse>(); | |
var result1 = batch.Get<GetStationResponse>(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Serializable] | |
public class Compound : RequestMessage, IRequestRespondsAs<CompoundResponse> | |
{ | |
public bool IsJson { get; set; } | |
public Dictionary<string, string> Values { get; set; } | |
} | |
[Serializable] | |
public class CompoundResponse : ResponseMessage | |
{ | |
public Dictionary<string, string> Result { get; set; } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class CompoundService : IService<Compound>, IRequiresRequestContext | |
{ | |
private static Dictionary<string, ServiceTuple> _serviceCache; | |
private class ServiceTuple | |
{ | |
public Type ServiceType { get; set; } | |
public Type MessageType { get; set; } | |
public Func<CompoundService, object, object> ServiceRunner { get; set; } | |
} | |
private static void CreateServiceCache() | |
{ | |
var services = (from t in EndpointHost.ServiceManager.ServiceController.ServiceTypes | |
where t.IsClass | |
&& !t.IsAbstract | |
let serviceInterface = t.GetInterface("IService`1") | |
where serviceInterface != null | |
let messageType = serviceInterface.GetGenericArguments().Single() | |
select new ServiceTuple | |
{ | |
ServiceType = t, | |
MessageType = messageType | |
}); | |
_serviceCache = services.ToDictionary(k => k.MessageType.Name); | |
} | |
private static readonly MethodInfo _resolveMethod = typeof(CompoundService) | |
.GetMethod("ResolveService", BindingFlags.NonPublic | BindingFlags.Instance); | |
private static Func<CompoundService, object, object> CreateServiceRunner(Type service, Type message) | |
{ | |
var getMethod = _resolveMethod.MakeGenericMethod(service); | |
var serviceParam = Expression.Parameter(typeof(CompoundService), "service"); | |
var callGet = Expression.Call(serviceParam, getMethod); | |
var messageParam = Expression.Parameter(typeof(object), "message"); | |
var executeMethod = typeof(IService<>).MakeGenericType(message) | |
.GetMethod("Execute"); | |
var responseParam = Expression.Variable(typeof(object), "response"); | |
var castToMessage = Expression.Convert(messageParam, message); | |
var callExecute = Expression.Call(callGet, executeMethod, castToMessage); | |
var assignToResponse = Expression.Assign(responseParam, callExecute); | |
var lambda = Expression.Lambda<Func<CompoundService, object, object>>(callExecute, serviceParam, messageParam); | |
return lambda.Compile(); | |
} | |
static CompoundService() | |
{ | |
CreateServiceCache(); | |
} | |
public object Execute(Compound request) | |
{ | |
var results = new Dictionary<string, string>(); | |
foreach (var kv in request.Values) | |
{ | |
ServiceTuple serviceTypes; | |
if (!_serviceCache.TryGetValue(kv.Key, out serviceTypes)) | |
{ | |
continue; | |
} | |
if (serviceTypes.ServiceRunner == null) | |
{ | |
serviceTypes.ServiceRunner = CreateServiceRunner(serviceTypes.ServiceType, serviceTypes.MessageType); | |
} | |
object message; | |
if (request.IsJson) | |
{ | |
message = JsonSerializer.DeserializeFromString(kv.Value, serviceTypes.MessageType); | |
} | |
else | |
{ | |
message = TypeSerializer.DeserializeFromString(kv.Value, serviceTypes.MessageType); | |
} | |
var response = serviceTypes.ServiceRunner(this, message); | |
string responseText; | |
if (request.IsJson) | |
{ | |
responseText = JsonSerializer.SerializeToString(response); | |
} | |
else | |
{ | |
responseText = TypeSerializer.SerializeToString(response); | |
} | |
results.Add(response.GetType().Name, responseText); | |
} | |
return new CompoundResponse | |
{ | |
Result = results | |
}; | |
} | |
protected T ResolveService<T>() | |
{ | |
var service = EndpointHost.AppHost.TryResolve<T>(); | |
var requiresContext = service as IRequiresRequestContext; | |
if (requiresContext != null) | |
{ | |
requiresContext.RequestContext = this.RequestContext; | |
} | |
return service; | |
} | |
public IRequestContext RequestContext { get; set; } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment