C# Templates and Unintended/Unexpected Inference - c#

I am working with a bunch of legacy web services and trying to come up with a streamlined approach to wrapping calls and checking the custom error types that may be returned. I think I am close but C# infers a different meaning from what I intended and I am not sure what I am doing wrong. I am hoping someone can point out my mistake:
I have added a simple interface to the client proxy of each of the legacy services and created an extension method for calling methods and looking at the responses (each service has its own error types but all boil down to a number and a message).
public static ApiResult<TModel,TResult> Call<TService,TResult,TModel>(this TService service, Func<TService,TResult> apiCall, TModel model)
where TService: ILegacyService
where TModel: BaseModel
{
ApiResult<TModel, TResult> result = default(ApiResult<TModel, TResult>);
try
{
TResult apiResult = apiCall(service);
/* extract/normalize custom, non-exception error types */
result = new ApiResult<TModel, TResult>(model, apiResult, normalizedErrors);
}
catch(Exception ex)
{
result = new ApiResult<TModel, TResult>(model, default(TResult), exception: ex);
}
return result;
}
Where the ApiResult type is like:
public class ApiResult<TModel,TResult>
{
public ApiResult(TModel model, TResult response,
NormalizedErrorCollection errorList = null, Exception exception = null) { ... }
}
My hope is to then have a chain of checks for specific errors much like a series of catch blocks that can assign human-friendly messages to an error model in BaseModel, e.g.
serviceInstance.Call(s => s.SomeMethod("Foo", 42), modelInstance)
.On<ServiceCode>(ServiceCode.MaxQty, m => m.Message = "No more for you")
.On<ServiceCode>(ServiceCode.NoID, m => m.Message = "Parent is gone")
.On<Exception>((m,e) => m.Message = "Unexpected error")
.Success((m,r) => m.Result = r.Result)
My problem is right at the top which the helper method which infers a meaning I did not intend:
CartService.Call(s => s.AddToCart(request.storeId, lineItem), model);
C#/VS state that the < Method Response Type > cannot be used as type parameter TModel and that there is no conversion between < Method Response Type > and BaseModel.
I cannot seem to figure out why the return type from the apiCall TResult is inferred to be the model type. Any help would be greatly appreciated! (Finding specific answers to template questions is equally difficult so I apologize if this matches an existing answer, but I did try and search first).

The error information in the comments above indicate that AddToCartResponse is not derived from BaseModel.

Related

Generic Extension Method for Dynamic Member Invocation

I am trying to build a generic extension method that can call a member function of a class dynamically and return a specified type. For some background, this is the general problem:
I am using Autorest to generate some client libraries for a swagger API. Because some GET routes within the API return different objects depending on the HTTP status code of the response, the method invocation returns object and the developer is responsible for casting the object themselves. I am trying to create a convenient wrapper for doing this cast in a generic way.
Here is an example of a typical function signature that would be wrapped up:
object IPet GetPets(string petName)
Note that this method might return a number of object types, depending on the HTTP status code. For instance, 200 might return a Dog object but 404 might return a Cat object.
This would be invoked through an Autorest generated client library like this:
AnimalApi animalClient = new AnimalApi(new Uri("http://myanimals.com"));
object pet = animalClient.Pet.GetPets("dog");
if(pet is Dog) {
Console.WriteLine("Dog!");
} else {
Console.WriteLine("Not Dog");
}
I would like to scoop up this manual casting functionality into something a bit more intuitive, here is what I am thinking:
AnimalApi animalClient = new AnimalApi(new Uri("http://myanimals.com"));
string petType = "Dog";
Dog pet = animalClient.Pet.CallMethod<IPet, Dog, string>( (api,type) => api.GetPets(type), petType);
In this scenario, any return other than objects of type 'Dog' would cause an exception to be thrown. Here is my attempt at implementation:
public static Tout CallMethod<Tin, Tout>(this Tin client, Expression<Action<Tin, Targ>> apiCall, params object[] args)
where Tout : class {
MethodCallExpression providedMethod = apiCall.Body as MethodCallExpression;
if(providedMethod == null) {
throw new ApplicationException("Invalid method call provded");
}
var method = providedMethod.Method;
object responseData;
try {
// Call object-returning function
responseData = method.Invoke(client, args);
} catch(Exception error) {
if(error.InnerException is HttpOperationException) {
// Unknown error occurred
var ex = error.InnerException as HttpOperationException;
object content = JsonConvert.DeserializeObject(ex.Response.Content);
throw new ServiceException(ex.Response.StatusCode + ": "
+ JsonConvert.SerializeObject(content));
} else {
throw error.InnerException;
}
}
// Return formatted object if successful
if(responseData is Tout) {
return responseData as Tout;
// Otherwise throw
} else {
// Deal with known error object responses
if(responseData is ErrorResponse) {
var error = responseData as ErrorResponse;
throw new ServiceException(error);
} else {
// Unknown error occurred
throw new ServiceException("Unknown response was received: "
+ JsonConvert.SerializeObject(responseData));
}
}
}
The problem I have here is of passing the function and arguments into the generic extension method. Without knowing the various possible numbers of arguments that might be required by the various API calls, how can I define Expression<Action<Tin, Targ>> generically? It seems to me like I would have to replicate this function with Expression<Action<T1, T2, T3>> and so on to accommodate varying length argumen lists.
I want an expressive way for people to interact with the API, such that it is easy to see what is happening. However, this mechanism should be robust to various API changes down the road. My current goal is to provide a way to encapsulate common object casting and error checking operations. Is there a better way to do this? For the moment I am working under the assumption that the server side swagger doc cannot change.

C# Generics and using the non-generic version from typed method

I'm using the RestSharp library to access a REST API.
I want all the API requests to go through the same method, so I can add headers, handle errors and do other stuff in a central place.
So I made a method that accepts a generic Func<> and that solves most of my problems, but I don't know how to handle the case where I don't have a return type.
private T PerformApiCall<T>(RestRequest restRequest, Func<RestRequest, IRestResponse<T>> restMethod)
{
var response = restMethod.Invoke(restRequest);
//handle errors
....
return response.Data;
}
I call it like this:
var apples = PerformApiCall(new RestRequest('/api/apples'), req => Client.Execute<List<Apple>>(req));
But I came across a problem, a bunch of API calls don't have a return type because they don't return data. So I used Client.Execute(req) and I get the error saying the type arguments cannot be inferred, I tried to pass , but that failed because it couldn't convert the non-generic IRestResponse to the typed one.
Any ideas on how to tackle this in a nice way?
One thing you could try is to add an overload to your PerformApiCall function that takes a Func with a non-generic result type, and returns nothing:
// Notice the `Func` has `IRestResponse`, not `IRestResponse<T>`
public void PerformApiCall(RestRequest restRequest,
Func<RestRequest, IRestResponse> restMethod)
...
Then, depending on how complex your error checking/logic is, you could move it out to a separate method (which returns the response), and call it from both overloads of PerformApiCall:
private T PerformRequestWithChecks<T>(RestRequest restRequest,
Func<RestRequest, T> restMethod)
where T : IRestResponse
{
var response = restMethod.Invoke(restRequest);
// Handle errors...
return response;
}
// You can use it from both versions of `PerformApiCall` like so:
//
// // From non-generic version
// var response =
// PerformRequestWithChecks<IRestResponse>(restRequest, restMethod);
//
// // From generic version
// var response =
// PerformRequestWithChecks<IRestResponse<T>>(restRequest, restMethod);
// return response.Data;
You were getting a compiler error because it is sound to treat a subtype as if it was an instance of its supertype, but it is not sound to do it in the other direction (which is what was happening when you changed your calling code to just Client.Execute(req), returning a non-generic).
Here's an ideone paste illustrating this: http://ideone.com/T2mQfl

Creating a Delegate from methodInfo in Mono 2.8.2

Hi I am trying to create a messenger in Mono 2.8.2 - the subset used by Unity3d. I thought it would be nifty to create a helper to auto subscribe methods to the messenger when they are decorated with a "subscribe" attribute.
I've been scratching my head over this and have read many of the other related stack questions without a solution to my problem. Frankly, I don't know if I am doing something wrong or if this is a bug in Mono.
foreach (var methodInfo in methods)
{
var attr = methodInfo.GetAttribute<SubscribeAttribute>();
if (attr == null)
continue;
var parmas = methodInfo.GetParameters();
if (parmas.Length != 1)
{
Debug.LogError("Subscription aborted. Invalid paramters.");
continue;
}
var type = parmas[0].ParameterType;
// Crashes here
// ArgumentException: method argument length mismatch
// I have tried many combinations..
// Direct typing of the message type and dynamic typing
var action = (Action<object>)Delegate.CreateDelegate(typeof(Action<object>), methodInfo);
// also does not work
// var dt = Expression.GetActionType(parmas.Select(o => o.ParameterType).ToArray());
// var action = Delegate.CreateDelegate(dt, methodInfo);
Subscribe(type, action, instance);
}
Any suggestions or work around would be appreciated.
Edit
The method signature looks like :
[Subscribe]
void OnMessage(object message){
// Hello World
}
Though, it was originally...
[Subscribe]
void OnTestMessage(TestMessage message){
// Hello World
}
It's a non-static method and you didn't provide a target object. Therefore Delegate.CreateDelegate will create an "open delegate" with an explicit this argument.
Because of the required this argument, it no longer matches the signature.

Ninject get target type from IBinding

I have an Interface that is implemented by several types. But before I do a kernel.GetAll<IAmServiceable>() I want to be able to ponder the target types of the injection.
I know the function kernel.GetBindings(typeof(IAmServiceable)) exists but this returns a list of IBinding's.
Does anyone know how I can get the target type from the IBinding?
I want to know the type that is bound to IAmServiceable before it gets instantiated.
I know it's probably a bit late now for your problem, but since i ran into this today, i thought others might too.
That's the code i finally came up with - i don't think its perfect (far from it), especially regarding performance, but it works for my case, and since i do not intend to call this method very often, it seems ok to me.
public Type GetBoundToType(IKernel kernel, Type boundType)
{
var binding = kernel.GetBindings(boundType).FirstOrDefault();
if (binding != null)
{
if (binding.Target != BindingTarget.Type && binding.Target != BindingTarget.Self)
{
// TODO: maybe the code below could work for other BindingTarget values, too, feelfree to try
throw new InvalidOperationException(string.Format("Cannot find the type to which {0} is bound to, because it is bound using a method, provider or constant ", boundType));
}
var req = kernel.CreateRequest(boundType, metadata => true, new IParameter[0], true, false);
var cache = kernel.Components.Get<ICache>();
var planner = kernel.Components.Get<IPlanner>();
var pipeline = kernel.Components.Get<IPipeline>();
var provider = binding.GetProvider(new Context(kernel, req, binding, cache, planner, pipeline));
return provider.Type;
}
if (boundType.IsClass && !boundType.IsAbstract)
{
return boundType;
}
throw new InvalidOperationException(string.Format("Cannot find the type to which {0} is bound to", boundType));
}
This is not possible. E.g what is the type In this case?
Bind<IX>().ToMethod(c => RandomBool() ? new Foo() : new Bar());
If you are working within a NinjectModule (or have access to an IKernel some other way) A nice simple approach would be:
var concreteType = Kernel.Get<InterfaceType>().GetType();
Obviously, the downside is you create an instance of the concrete type. It is nevertheless nice and simple and I think pretty robust. Obviously, if the interface derives from IDisposable you would use a using statement:
using(var obj = Kernel.Get<InterfaceType>())
{
var concreteType = obj.GetType();
.
.
.
}

How to decide at runtime which type to pass as a generic parameter?

I have several message queues that have specific messages on them.
I've created classes for these messages using xsd.exe.
I can receive a message syncronously and deseriazlise it with this method:
public oneOfMyTypes DeserializeMessage(XDocument message)
{
var serializer = new XmlSerializer(typeof(oneOfMyTypes));
var entity = (oneOfMyTypes)serializer.Deserialize(message.CreateReader());
return entity;
}
I then persist the entity via Fluent NHibernate.
So I've got about five message queues that all have their own type of message.
I would like to keep this little processor app maintainable, so that adding more message queues and message types doesn't become a pain.
So I have a list of queue names in my app.config that I use to create the message queues on start up and then I want to wire up a single method to the .ReceiveCompleted event of all queues:
void queue_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
{
var queue = (MessageQueue)sender;
var message = queue.EndReceive(e.AsyncResult);
var body = message.Body.ToString();
var xml = XDocument.Parse(body);
var queueName = queue.QueueName;
Type entityType = GetTypeFromQueueName(queueName);
entityType entity = DeserializeMessage<entityType>(xml);
var repository = new LogRepository();
repository.AddEntity<entityType>(entity);
}
private T DeserializeMessage<T>(XDocument message)
{
var serializer = new XmlSerializer(typeof(T));
var entity = (T)serializer.Deserialize(message.CreateReader());
return entity;
}
public Type GetTypeFromQueueName(string queueName)
{
switch (queueName)
{
case "some-message-queue-name":
return typeof (oneOfMyTypes);
}
}
But when I try to pass entityType to the generic methods I get "Type or namespace name expected".
I'm probably doing something really silly, but I can't figure out how this should work.
I've tried using the dynamic keyword and also .MakeGenericType but no luck.
I've also looked at:
Dynamic Generic declaration of type T
Function returning a generic type whose value is known only at runtime
Determining a Generic Type at Runtime in Non-Generic Class
How to pass variable of type "Type" to generic parameter
But I'm still not getting it ... help?
Unfortunately, generics are not meant to function dynamically like this. Generic parameters must be defined at design time. It's been a while since I've used NHibernate, but isn't there a way to insert entities with a syntax like:
repository.AddEntity(entity, typeof(myEntityType));
EDIT:
or
Session.SaveOrUpdate(object);
This link should help you
http://todotnet.com/post/2006/11/13/Instantiating-Generic-Types-at-runtime.aspx
You should be able to go from the link i posted to call the methode through reflection.
See the following link:
http://www.victorchen.info/call-static-method-with-a-string-name/
So basically when you've created your generic Type, you then grab the MethodInfo of your static method and then call the Invoke method on the MethodInfo object.
(i haven't actually tried this but in theory i believe it should work)

Categories

Resources