Validating model properties WCF Web APi - c#

I have a set of services hosted with WCF Web Api, what I need to do is validate the properties inside the models of the app.
In MVC 3 for example I decorate properties in the model like this:
[StringLength(30)]
public string UserName { get; set; }
and then in the controller I proceed like this to verify os the model has met the validation parameters:
[HttpPost]
ActionResult Create(Model myModel)
{
if(ModelState.IsValid(){
Post the model
}
else
{
Don't post the model
}
}
Is there a way to do something similar in WCF Web Api?

Ok I finally managed to get validations for my models working. I wrote a validation handler and a couple of extensions methods. First thing the validation handler:
public class ValidationHandler<T> : HttpOperationHandler
{
private readonly HttpOperationDescription _httpOperationDescription;
public ValidationHandler(HttpOperationDescription httpOperationDescription)
{
_httpOperationDescription = httpOperationDescription;
}
protected override IEnumerable<HttpParameter> OnGetInputParameters()
{
return _httpOperationDescription.InputParameters
.Where(prm => prm.ParameterType == typeof(T));
}
protected override IEnumerable<HttpParameter> OnGetOutputParameters()
{
return _httpOperationDescription.InputParameters
.Where(prm => prm.ParameterType == typeof(T));
}
protected override object[] OnHandle(object[] input)
{
var model = input[0];
var validationResults = new List<ValidationResult>();
var context = new ValidationContext(model, null, null);
Validator.TryValidateObject(model, context, validationResults,true);
if (validationResults.Count == 0)
{
return input;
}
else
{
var response = new HttpResponseMessage()
{
Content = new StringContent("Model Error"),
StatusCode = HttpStatusCode.BadRequest
};
throw new HttpResponseException(response);
}
}
}
Notice how the Handler receives a T object, this is mainly because I would like to validate all the model types within the API. So the OnGetInputParameters specifies that the handler needs to receive a T type object, and the OnGetOutputParameters specifies that the handler needs to return an object with the same T type in case validations policies are met, if not, see how the on handle method throws an exception letting the client know that there's been a validation problem.
Now I need to register the handler, for this I wrote a couple of extensions method, following an example of a Pedro Felix's blog http://pfelix.wordpress.com/2011/09/24/wcf-web-apicustom-parameter-conversion/ (this blog helped me a lot, there are some nice explanations about the whole handler operations thing). So these are the extensions methods:
public static WebApiConfiguration ModelValidationFor<T>(this WebApiConfiguration conf)
{
conf.AddRequestHandlers((coll, ep, desc) =>
{
if (desc.InputParameters.Any(p => p.ParameterType == typeof(T)))
{
coll.Add(new ValidationHandler<T>(desc));
}
});
return conf;
}
so this methos checks if there is a T type parameter in the operations, and if so, it adds the handler to that specific operation.
This one calls the other extension method AddRequestHandler, and that method add the new handler without removing the previous registered ones, if the exist.
public static WebApiConfiguration AddRequestHandlers(
this WebApiConfiguration conf,
Action<Collection<HttpOperationHandler>,ServiceEndpoint,HttpOperationDescription> requestHandlerDelegate)
{
var old = conf.RequestHandlers;
conf.RequestHandlers = old == null ? requestHandlerDelegate :
(coll, ep, desc) =>
{
old(coll, ep, desc);
};
return conf;
}
The last thing is to register the handler:
var config = new WebApiConfiguration();
config.ModelValidationFor<T>(); //Instead of passing a T object pass the object you want to validate
routes.SetDefaultHttpConfiguration(config);
routes.MapServiceRoute<YourResourceObject>("SomeRoute");
So this is it.. Hope it helps somebody else!!

I am currently working on a HttpOperationHandler that does exactly what you need. It's not done by now, but this psuedo code might give you an idea of how you can do it.
public class ValidationHandler : HttpOperationHandler
{
private readonly HttpOperationDescription _httpOperationDescription;
private readonly Uri _baseAddress;
public ValidationHandler(HttpOperationDescription httpOperationDescription, Uri baseAddress)
{
_httpOperationDescription = httpOperationDescription;
_baseAddress = baseAddress;
}
protected override IEnumerable<HttpParameter> OnGetInputParameters()
{
return new[] { HttpParameter.RequestMessage };
}
protected override IEnumerable<HttpParameter> OnGetOutputParameters()
{
var types = _httpOperationDescription.InputParameters.Select(x => x.ParameterType);
return types.Select(type => new HttpParameter(type.Name, type));
}
protected override object[] OnHandle(object[] input)
{
var request = (HttpRequestMessage)input[0];
var uriTemplate = _httpOperationDescription.GetUriTemplate();
var uriTemplateMatch = uriTemplate.Match(_baseAddress, request.RequestUri);
var validationResults = new List<ValidationResult>();
//Bind the values from uriTemplateMatch.BoundVariables to a model
//Do the validation with Validator.TryValidateObject and add the results to validationResults
//Throw a exception with BadRequest http status code and add the validationResults to the message
//Return an object array with instances of the types returned from the OnGetOutputParmeters with the bounded values
}
}
The OnGetInputParameters value tells what's expected into the OnHandle method, and the OnGetOutputParameters tells what's the expected output from the OnHandle method (which later on is injected into the method in the service).
You can then add the handler to the routing with a HttpConfiguration as follows:
var httpConfiguration = new HttpConfiguration
{
RequestHandlers = (collection, endpoint, operation) => collection.Add(new ValidationHandler(operation, endpoint.Address.Uri))
};
RouteTable.Routes.MapServiceRoute<MyResource>("MyResource", httpConfiguration);

There is an example of this posted on MSDN of creating a behavior for this that should work. You could also call the validators manually with Validator.ValidateObject (or wrap it as an extension method) and return the validation errors, which is essentially what that behavior is doing.

Firstly I should say awesome question+answer Daniel
However, I've taken it a little further, refined it and added to it.
ValidationHander
I've refined this a little. It is now based on a generic HttpOperationHandler so it can take the HttpRequestMessage. The reason for this is so that I can return error messages formatted using the correct media type (from the accept header).
public class ValidationHandler<TResource> : HttpOperationHandler<TResource, HttpRequestMessage, HttpRequestMessage>
{
public ValidationHandler() : base("response") { }
protected override HttpRequestMessage OnHandle(TResource model, HttpRequestMessage requestMessage)
{
var results = new List<ValidationResult>();
var context = new ValidationContext(model, null, null);
Validator.TryValidateObject(model, context, results, true);
if (results.Count == 0)
{
return requestMessage;
}
var errorMessages = results.Select(x => x.ErrorMessage).ToArray();
var mediaType = requestMessage.Headers.Accept.FirstOrDefault();
var response = new RestValidationFailure(errorMessages);
if (mediaType != null)
{
response.Content = new ObjectContent(typeof (string[]), errorMessages, mediaType);
}
throw new HttpResponseException(response);
}
}
Extension Methods
The 2 you provided stay virtually the same about from the desc paramter no longer being needed when adding the ValidationHandler in the ModelValidationFor method
I've added an extra extension method. This is to make sure that all "Resource" classes are validated. This is mainly me being lazy and forgetful. I am forever forgetting to add some class to a list somewhere. (It's why I write generic windsor installers!)
public static void ValidateAllResourceTypes(this WebApiConfiguration config, string assemblyFilter = "MyCompany*.dll")
{
var path = Path.GetDirectoryName((new Uri(Assembly.GetExecutingAssembly().CodeBase)).AbsolutePath);
var dc = new DirectoryCatalog(path, assemblyFilter);
var assemblies = dc.LoadedFiles.Select(Assembly.LoadFrom).ToList();
assemblies.ForEach(assembly =>
{
var resourceTypes = assembly.GetTypes()
.Where(t => t.Namespace != null && t.Namespace.EndsWith("Resources"));
foreach (var resourceType in resourceTypes)
{
var configType = typeof(Extensions);
var mi = configType.GetMethod("ModelValidationFor");
var mi2 = mi.MakeGenericMethod(resourceType);
mi2.Invoke(null, new object[] { config });
}
});
}
I made use of the System.ComponentModel.Composition.Hosting namespace (formerly known as MEF) for the DirectoryCatalog class. In this case I've just used the namespace ending with "Resources" to find my "Resource" classes. It wouldn't take much work to change it to use a custom attribute or whatever other way you might prefer to identify which classes are your "Resources".
RestValidationFailure
This is a little helper class I made to allow consistent behaviour for validation failure responses.
public class RestValidationFailure : HttpResponseMessage
{
public RestValidationFailure(string[] messages)
{
StatusCode = HttpStatusCode.BadRequest;
foreach (var errorMessage in messages)
{
Headers.Add("X-Validation-Error", errorMessage);
}
}
}
So, now I get a nice list (in my preferred mediatype) of all the validation errors.
Enjoy! :)

Related

Ninject just won't register MediatR.IRequestHandler<,> using convention-based binding?

As per following example:
MediatR.Examples.Ninject
I've a MediatorModule class as follows:
public class MediatorModule : NinjectModule {
public class ContravariantBindingResolver : NinjectComponent, IBindingResolver {
public IEnumerable<IBinding> Resolve(Multimap<Type, IBinding> bindings, Type service) {
if (service.IsGenericType) {
var genericType = service.GetGenericTypeDefinition();
var genericArguments = genericType.GetGenericArguments();
if (1 == genericArguments.Count() && genericArguments.Single().GenericParameterAttributes.HasFlag(GenericParameterAttributes.Contravariant)) {
var argument = service.GetGenericArguments().Single();
var matches = bindings.Where(kvp => kvp.Key.IsGenericType
&& kvp.Key.GetGenericTypeDefinition().Equals(genericType)
&& kvp.Key.GetGenericArguments().Single() != argument
&& kvp.Key.GetGenericArguments().Single().IsAssignableFrom(argument))
.SelectMany(kvp => kvp.Value);
return matches;
}
}
return Enumerable.Empty<IBinding>();
}
}
public override void Load() {
Kernel.Components.Add<IBindingResolver, ContravariantBindingResolver>();
Kernel.Bind(services => services.FromAssemblyContaining<IMediator>().SelectAllClasses().BindDefaultInterface());
Kernel.Bind(services => services.FromThisAssembly().SelectAllClasses().InheritedFrom(typeof(IRequestHandler<,>)).BindAllInterfaces());
Kernel.Bind(services => services.FromThisAssembly().SelectAllClasses().InheritedFrom(typeof(INotificationHandler<>)).BindAllInterfaces());
Kernel.Bind(typeof(IPipelineBehavior<,>)).To(typeof(RequestPreProcessorBehavior<,>));
Kernel.Bind(typeof(IPipelineBehavior<,>)).To(typeof(RequestPostProcessorBehavior<,>));
Kernel.Bind(typeof(IPipelineBehavior<,>)).To(typeof(RequestExceptionActionProcessorBehavior<,>));
Kernel.Bind(typeof(IPipelineBehavior<,>)).To(typeof(RequestExceptionProcessorBehavior<,>));
Kernel.Bind<ServiceFactory>().ToMethod(ctx => t => ctx.Kernel.TryGet(t));
}
}
On a Quick Watch over services.FromThisAssembly().SelectAllClasses().InheritedFrom(typeof(IRequestHandler<,>)), I can see that the classes are correctly found.
And here is an example of my command and handler.
public class SupplierInvoice {
public class ProcessCommand : IRequest<ProcessedTransaction> {
public ProcessCommand(XmlDocument supplierInvoiceDocument)
=> SupplierInvoiceDocument = supplierInvoiceDocument;
public XmlDocument SupplierInvoiceDocument { get; }
}
public class ProcessCommandHandler : IRequestHandler<ProcessCommand, ProcessedTransaction> {
private readonly IXmlSerializer<SupplierInvoice> _serializer;
private readonly IValidator<SupplierInvoice> _validator;
private readonly IMediator _mediator;
public ProcessCommandHandler(IXmlSerializer<SupplierInvoice> serializer, IValidator<SupplierInvoice> validator, IMediator mediator) {
_serializer=serializer;
_validator=validator;
_mediator=mediator;
}
public async Task<ProcessedTransaction> Handle(ProcessCommand request, CancellationToken cancellationToken) {
if (request == null) return ProcessedTransaction.Succeeded;
var model = _serializer.Deserialize(request.SupplierInvoiceDocument.OuterXml);
var vr = _validator.Validate(model);
if (!vr.IsValid) // throwing exception with validation messages.
return await _mediator.Send(new CreateCommand(model));
}
}
}
So I wonder how can the handlers be not registered using the BindAllInterfaces method?
Even using plain old binding syntax, the request handlers just won't get registered.
Kernel.Bind<IRequestHandler<SupplierInvoice.ProcessCommand, ProcessedTransaction>>().To<SupplierInvoice.ProcessCommandHandler>();
What am I missing?
As per linked Ninject example: MediatR.Examples.Ninject, I guess I found an error in the ContravariantBindingResolver.cs class.
The line that I guess is at fault is when getting the generic arguments for the second time.
var genericType = service.GetGenericTypeDefinition();
var genericArguments = genericType.GetGenericArguments();
if (genericArguments.Count() == 1
&& genericArguments.Single().GenericParameterAttributes.HasFlag(GenericParameterAttributes.Contravariant))
{
var argument = service.GetGenericArguments().Single();
var matches = bindings.Where(kvp => kvp.Key.IsGenericType
&& kvp.Key.GetGenericTypeDefinition().Equals(genericType)
&& kvp.Key.GetGenericArguments().Single() != argument
&& kvp.Key.GetGenericArguments().Single().IsAssignableFrom(argument))
.SelectMany(kvp => kvp.Value);
return matches;
}
Notice that var genericArguments = genericType.GetGenericArguments() uses the generic type definition returned by the service.GetGenericTypeDefinition() method call. But because in the sample code provided the second call to GetGenericArguments is made from the service instance, the correct generic parameter doesn't seem to be returned adequately. Hence I'd recommend the use of the already declared variable which contains the generic arguments from which the argument variable's value can be obtained.
To sum it up, for me what made the resolver actually resolve the correct handler every time is that I changed this line:
var argument = service.GetGenericArguments().Single()
to
var argument = genericArguments.Single()
given it is contravariant, so only available argument since the check is already made for the length of the returned arguments array.
Changing this for me made the difference between the unregistered handler exception to a working code able to resolve proper handlers.

Abstract class model binding in asp.net core web api 2

I have been trying to figure out how to use custom model binding with .net Core 2 web api but have not been able to get it working.
I have been through some articles as below
http://www.palmmedia.de/Blog/2018/5/13/aspnet-core-model-binding-of-abstract-classes
Asp net core rc2. Abstract class model binding
In my case, the bindingContext.ModelName is always empty. Can anybody explain why this could be?
Sample implementation below
Controller
public IActionResult SomeAction([ModelBinder(BinderType = typeof(BlahTypeModelBinder))][FromBody]TheBaseClass theBase)
{
return Ok();
}
Models
public abstract class TheBaseClass
{
public abstract int WhatType { get; }
}
public class A : TheBaseClass
{
public override int WhatType { get { return 1; } }
}
public class B : TheBaseClass
{
public override int WhatType { get { return 2; } }
}
Provider
public class BhalTypeBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
if (context.Metadata.ModelType == typeof(TheBaseClass))
{
var assembly = typeof(TheBaseClass).Assembly;
var abstractSearchClasses = assembly.GetExportedTypes()
.Where(t => t.BaseType.Equals(typeof(TheBaseClass)))
.Where(t => !t.IsAbstract)
.ToList();
var modelBuilderByType = new Dictionary<Type, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder>();
foreach (var type in abstractSearchClasses)
{
var propertyBinders = new Dictionary<ModelMetadata, IModelBinder>();
var metadata = context.MetadataProvider.GetMetadataForType(type);
foreach (var property in metadata.Properties)
{
propertyBinders.Add(property, context.CreateBinder(property));
}
modelBuilderByType.Add(type, new Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder(propertyBinders));
}
return new BlahTypeModelBinder(modelBuilderByType, context.MetadataProvider);
}
return null;
}
}
Binder
public class BlahTypeModelBinder : IModelBinder
{
private readonly IModelMetadataProvider _metadataProvider;
private readonly IDictionary<Type, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder> _binders;
public BlahTypeModelBinder(IDictionary<Type, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder> binders, IModelMetadataProvider metadataProvider)
{
_metadataProvider = metadataProvider;
_binders = binders;
}
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
throw new ArgumentNullException(nameof(bindingContext));
var modelTypeValue = bindingContext.ValueProvider.GetValue(ModelNames.CreatePropertyModelName(bindingContext.ModelName, "WhatType"));
if (modelTypeValue != null && modelTypeValue.FirstValue != null)
{
Type modelType = Type.GetType(modelTypeValue.FirstValue);
if (this._binders.TryGetValue(modelType, out var modelBinder))
{
ModelBindingContext innerModelBindingContext = DefaultModelBindingContext.CreateBindingContext(
bindingContext.ActionContext,
bindingContext.ValueProvider,
this._metadataProvider.GetMetadataForType(modelType),
null,
bindingContext.ModelName);
/*modelBinder*/
this._binders.First().Value.BindModelAsync(innerModelBindingContext);
bindingContext.Result = innerModelBindingContext.Result;
return Task.CompletedTask;
}
}
//More code
}
}
I finally managed to solve the issue. You dont need the provider. Just the following binder works
public class BlahTypeModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
throw new ArgumentNullException(nameof(bindingContext));
var json = ExtractRequestJson(bindingContext.ActionContext);
var jObject = Newtonsoft.Json.Linq.JObject.Parse(json);
var whatTypeInt = (int)jObject.SelectToken("WhatType");
if (whatTypeInt == 1)
{
var obj = DeserializeObject<A>(json);
bindingContext.Result = ModelBindingResult.Success(obj);
}
else if (whatTypeInt == 2)
{
var obj = DeserializeObject<B>(json);
bindingContext.Result = ModelBindingResult.Success(obj);
}
else
{
bindingContext.Result = ModelBindingResult.Failed();
return Task.CompletedTask;
}
return Task.CompletedTask;
}
private static string ExtractRequestJson(ActionContext actionContext)
{
var content = actionContext.HttpContext.Request.Body;
return new StreamReader(content).ReadToEnd();
}
private static T DeserializeObject<T>(string json)
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(json, new Newtonsoft.Json.JsonSerializerSettings
{
TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto
});
}
}
The examples you linked to use an external query string parameter to determine the type.
If you call your action like this: SomeAction?WhatType=YourNamespaceName.A the binding works as expected.
bindingContext.ModelName being empty is just fine, it would be set after model binding. You can set it after setting bindingContext.Result if you want. Parameter WhatType comes from the QueryStringValueProvider, so no prefix is fine.
How to accomplish abstract model binding based on the JSON alone
To do this, we need:
A value provider to read the JSON and provide us with some "WhatType" value, in place of the QueryStringValueProvider.
Some reflection to map the extracted numbers to the Type-s.
1. ValueProvider
There is a detailed article on creating ValueProviders here:
As a starting point here is some code that successfully extracts the WhatType integers from the body json:
public class BlahValueProvider : IValueProvider
{
private readonly string _requestBody;
public BlahValueProvider(string requestBody)
{
_requestBody = requestBody;
}
private const string PROPERTY_NAME = "WhatType";
public bool ContainsPrefix(string prefix)
{
return prefix == PROPERTY_NAME;
}
public ValueProviderResult GetValue(string key)
{
if (key != PROPERTY_NAME)
return ValueProviderResult.None;
// parse json
try
{
var json = JObject.Parse(_requestBody);
return new ValueProviderResult(json.Value<int>("WhatType").ToString());
}
catch (Exception e)
{
// TODO: error handling
throw;
}
}
}
public class BlahValueProviderFactory : IValueProviderFactory
{
public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var request = context.ActionContext.HttpContext.Request;
if (request.ContentType == "application/json")
{
return AddValueProviderAsync(context);
}
return Task.CompletedTask;
}
private Task AddValueProviderAsync(ValueProviderFactoryContext context)
{
using (StreamReader sr = new StreamReader(context.ActionContext.HttpContext.Request.Body))
{
string bodyString = sr.ReadToEnd();
context.ValueProviders.Add(new BlahValueProvider(bodyString));
}
return Task.CompletedTask;
}
}
Of course you have to register this factory in Startup.cs just as you registered the model binder. And this absolutely misses converting the extracted number to the actual Type (for this, see point 2 below), but if you place a breakpoint on your line staring with if (modelTypeValue != null you can see that modelTypeValue is there for you now even without the separate GET parameter.
2. Reflection
Realize that you are trying to figure out the type based on a property that is dynamically calculated on an existing instance (they are not static). While by knowing the current implementation I know that this is possible (create an empty instance of the model, check the WhatType property, throw the instance away), this is very bad practice, as nothing guarantees that an instance property is statically constant.
The clean solution for this would be an Attribute, that contains the WhatType number for that class. Then we can reflect on that attribute and build a map that maps ints to Types. This is out of the scope if this question, but look up any custom attribute tutorial if you are not familiar, and you will be able to put it together really quickly.

Serialization of nested Action<T> for service bus Queue

The general consensus from reading other posts is that serializing anonymous delegates and actions etc is a bad idea and brittle etc. The lifetime of these serialized actions will be very short lived but i'm open to better ideas about how to accomplish what i'm doing.
I have a web role and a worker role. The user can upload massive amounts of data that I need to split down and send to external wcf services. I need to queue this data and I just wanted a generic interface. I'd like to be able to deserialize it and call Execute() on it without having custom logic in the worker role.
I have 4 external services (may grow) each with multiple calls and there own unique parameters. I wanted a method of constructing the parameters in the web role, declaring which serviceInvoker class and interface I want to construct (generates a ChannelFactory with client credentials etc), and executing the child method with said parameters.
// Code
var queueMessage = new WorkOutMessage<IService1>(User.agent.Client.Id,
new Action<ServiceInvoker<IService1>>(serviceInvoker =>
serviceInvoker.InvokeService(proxy =>
{
using (new OperationContextScope((IContextChannel)proxy))
{
OperationContext.Current.OutgoingMessageHeaders.ReplyTo = new EndpointAddress("https://someAddress.com/");
OperationContext.Current.OutgoingMessageHeaders.MessageId = new System.Xml.UniqueId(head.CorrelationID);
proxy.SomeChildFunction(envelope);
}
})));
var stream = new MemoryStream();
var formatter = new BinaryFormatter();
formatter.Serialize(stream, queueMessage;
var brokeredMessage = new BrokeredMessage(stream) { CorrelationId = correlationId };
// Formatter.Serialize throws an exception
Type '<MyController>+<>c__DisplayClassc' in Assembly '<MyDll>, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
// Classes
public interface IQueueProxyMessage
{
int Attempts();
bool Execute();
}
[Serializable]
public class WorkOutMessage<T> : IQueueProxyMessage where T : class
{
public Guid clientId { get; set; }
public Action<ServiceInvoker<T>> action { get; set; }
public int attempts { get; set; }
public WorkOutMessage(Guid clientId, Action<ServiceInvoker<T>> action)
{
this.clientId = clientId;
this.action = action;
this.attempts = 0;
}
public int Attempts()
{
return this.attempts;
}
public bool Execute()
{
this.attempts++;
try
{
var config = InfrastructureConfiguration.Instance;
var storage = new AzureStorageService();
var db = new DbContext(config.azure.dbConnectionString,
DbValidationMode.Enabled,
DbLazyLoadingMode.Disabled,
DbAutoDetectMode.Enabled);
var client = db.Client.Include(x => x.Organisation)
.Include(x => x.Certificate)
.Where(x => x.Active
&& x.Organisation.Active
&& x.Certificate != null
&& x.Id == this.clientId)
.FirstOrDefault();
if(client != null)
{
X509Certificate2 clientCert;
string clientCertContentType;
byte[] clientCertContent;
if (storage.GetBlob(AzureBlobType.Certificate, client.Certificate.StorageId.ToString(), out clientCertContentType, out clientCertContent))
{
var base64EncodedBytes = Encoding.Unicode.GetString(clientCertContent);
clientCert = new X509Certificate2(Convert.FromBase64String(base64EncodedBytes), "test", X509KeyStorageFlags.PersistKeySet);
if(clientCert != null)
{
var serviceInvoker = new ServiceInvoker<T>(client.Id, "test", clientCert, config.publicCertificate);
if(serviceInvoker != null)
{
this.action.Invoke(serviceInvoker);
}
// error
}
// error
}
// error
}
else
{
}
return true;
}
catch (Exception ex)
{
return false;
}
}
Obviously my serialization knowledge is pretty non-existant. which is why I thought this would work in the first place. Is there any way to re-architect this so I can still specify what serviceInvoker to use, what method and pass the parameters?
Edit: the code where I try to use BinaryFormatter and Exception
Edit2: This is a bad idea, i'm going to pass the data and reconstruct the class on the worker.

Can I inject a dependency into a ServiceStack Request Filter?

I can successfully inject dependencies into my ServiceStack services but now I have a need to inject a dependency into a Request Filter. However this does not appear to work the same way.
Here's my filter (it simply checks whether the source IP is in an approved list; it is this list I'm trying to inject):
public class CheckIPFilter : RequestFilterAttribute
{
private readonly IList<string> _IPAddresses = new List<string>();
public CheckIPFilter() { }
public CheckIPFilter(IList<string> IPAddresses)
{
_IPAddresses = IPAddresses;
}
public override void Execute(ServiceStack.ServiceHost.IHttpRequest req, ServiceStack.ServiceHost.IHttpResponse res, object requestDto)
{
if (!_IPAddresses.Contains(req.UserHostAddress))
{
var errResponse = DtoUtils.CreateErrorResponse("401", "Unauthorised", null);
var responseDto = DtoUtils.CreateResponseDto(requestDto, new ResponseStatus("401", "Unauthorised"));
var contentType = req.ResponseContentType;
var serializer = EndpointHost.AppHost.ContentTypeFilters.GetResponseSerializer(contentType);
res.ContentType = contentType;
var serializationContext = new HttpRequestContext(req, res, responseDto);
serializer(serializationContext, responseDto, res);
res.EndRequest(); //stops further execution of this request
return;
}
}
}
This is what's in my global.asax:
var IPAddresses = new List<string>()
{ "99.99.99.99", "99.99.99.99", "99.99.99.99", "99.99.99.99" };
container.Register<IList<string>>(IPAddresses);
_IPAddresses is always null.
I guess I must be missing something basic here. Is there a better way of approaching this?
Use property injection instead of constructor injection for filter attributes, since they are cloned and public properties auto-wired and not created like everything else that is instantiated from the IOC and auto-wired.

Using Moq to modify the argument to a stubbed void method

I have a bit of a perfect storm that's preventing me from testing a class. The class is a RestClient that's wrapping an in-house HttpClient (which I cannot modify). The ExecuteMethod method on the HttpClient is void. It accepts an IHttpMethod, and it modifies this object based on the response from the server. I want to mock out ExecuteMethod so that it modifies the IHttpMethod for me. I'm trying to use Callback to achieve this, but it's not working.
Here's the code that sends the request:
var httpClient = this.httpClientFactory.CreateHttpClient();
httpClient.ExecuteMethod(method);
var response = this.GetResourceResponse<T>(method.ResponseBodyAsStream.AsString());
response.ResponseHeaders = method.ResponseHeaders;
response.Status = method.StatusCode.ToString();
response.StatusCode = (int)method.StatusCode;
return response;
And here's my attempt at mocking:
var mockHttpMethod = new Mock<IHttpMethod>();
mockHttpMethod.Setup(m => m.ResponseBodyAsStream).Returns(new MemoryStream(Encoding.UTF8.GetBytes("foo")));
var modifyHttpMethod = new Action<IHttpMethod>(m =>
{
m = mockHttpMethod.Object;
});
var mockHttpClient = new Mock<IHttpClient>();
mockHttpClient.Setup(c => c.ExecuteMethod(It.IsAny<IHttpMethod>()))
.Callback<IHttpMethod>(modifyHttpMethod);
var mockHttpClientFactory = new Mock<ILegalHoldHttpClientFactory>();
mockHttpClientFactory.Setup(f => f.CreateHttpClient()).Returns(mockHttpClient.Object);
var restClient = new RestClient(mockHttpClientFactory.Object);
When the modifyHttpMethod action is executed, I observe two things, both of which I expect:
The incoming IHttpMethod (m) has the properties I expect it to have.
After assigning the mock object to m, it contains the stubbed values that I setup in my test.
However, after the callback is executed and control is returned to my application code, my method variable still has its old values that I saw in step 1 above, which causes a null reference exception when trying to read method.ResponseBodyAsStream.
Is what I'm trying to do even achievable? If so, how? Thanks!
I've replicated your setup vis a vis mocking, and can't find any issues with it:
public interface IHttpMethod
{
MemoryStream ResponseBodyAsStream { get; set; }
}
public interface IHttpClient
{
void ExecuteMethod(IHttpMethod method);
}
public class HttpClient : IHttpClient
{
#region IHttpClient Members
public void ExecuteMethod(IHttpMethod method)
{
}
#endregion
}
public class Factory
{
public virtual IHttpClient CreateHttpClient()
{
return new HttpClient();
}
}
public class ClassUnderTest
{
private readonly Factory _factory;
public ClassUnderTest(Factory factory)
{
_factory = factory;
}
public string GetResponseAsString(IHttpMethod method)
{
var myClient = _factory.CreateHttpClient();
myClient.ExecuteMethod(method);
return method.ResponseBodyAsStream.ToString();
}
}
[TestClass]
public class ScratchPadTest
{
[TestMethod]
public void SampleTest()
{
var mockHttpMethod = new Mock<IHttpMethod>();
mockHttpMethod.Setup(x => x.ResponseBodyAsStream).Returns(new MemoryStream(Encoding.UTF8.GetBytes("foo")));
var modifyHttpMethod = new Action<IHttpMethod>(m =>
{
m = mockHttpMethod.Object;
});
var mockHttpClient = new Mock<IHttpClient>();
mockHttpClient.Setup(c => c.ExecuteMethod(It.IsAny<IHttpMethod>())).Callback<IHttpMethod>(modifyHttpMethod);
var myFactoryStub = new Mock<Factory>();
myFactoryStub.Setup(f => f.CreateHttpClient()).Returns(mockHttpClient.Object);
var myCut = new ClassUnderTest(myFactoryStub.Object);
Assert.IsNotNull(myCut.GetResponseAsString(mockHttpMethod.Object));
}
}
That test passes, meaning that the memory stream is not null (otherwise an exception would be generated). The only X factor that I can see is your AsString() extension method (I'm assuming that's an extension method as intellisense doesn't show it to me on MemoryStream). Could your problem be in there?
And, by the way, what you're trying to do is almost certainly achievable with Moq.

Categories

Resources