I've created a custom DataAnnotationsModelValidatorProvider:
public class CustomValidatorProvider : DataAnnotationsModelValidatorProvider
{
protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
{
//Do custom stuff...
return base.GetValidators(metadata, context, attributes);
}
}
And I've registered it in my Global.asax:
ModelValidatorProviders.Providers.Add(new CustomValidatorProvider());
I put a breakpoint in the GetValidators method but it is never hit. My understanding is that this custom validator provider should be executed for each property in my model. Am I missing something?
I think you need to override from ModelValidatorProvider and not DataAnnotationsModelValidatorProvider. And the method signature should not have the attributes parameter and should be public:
public class CustomValidatorProvider : ModelValidatorProvider
{
public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context)
{
//Do custom stuff...
//You cannot call the base here as ModelValidatorProvider is abstract.
//return base.GetValidators(metadata, context);
}
}
ModelValidatorProviders.Providers already contain a DataAnnotationsModelValidatorProvider.
Simply remove it before adding your custom DataAnnotationsModelValidatorProvider.
ModelValidatorProviders.Providers.Remove(ModelValidatorProviders.Providers.OfType<DataAnnotationsModelValidatorProvider>().First());
ModelValidatorProviders.Providers.Add(new DependencyResolverModelValidatorProvider());
Related
How do I inject the database to my TestAttribute class as .net core does magically to my controller.
services.AddScoped<DbContextOptions>(p => p.GetRequiredService<DbContextOptions<Context>>());
services.TryAdd(new ServiceDescriptor(typeof(Context), typeof(Context), ServiceLifetime.Transient));
services.AddMvc(options =>
{
options.Filters.Add(new TestAttribute(/*need parameter*/));
}
public HouseController([FromServices] Context database)
{
this.Database = database;
}
public class TestAttribute : ActionFilterAttribute
{
public TestAttribute([FromServices] Context database)
{
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
}
}
To inject dependencies into Filters you need to use the ServiceFilter attribute (see docs)
Manually injecting it to an controller action
[ServiceFilter(typeof(TestAttribute))]
public Task<IActionResult> Index()
{
...
}
Also your registration is wrong in the startup for all actions! Filters.Add() accepts a Type, when you want to use attributes which require dependencies (because you can't instantiate them in code), see "Filter Scopes" in the docs.
services.AddMvc(options =>
{
options.Filters.Add(typeof(TestAttribute));
}
I want to access RouteTemplate inside custom action filter in my Web Api Project.
I have registered a custom action filter to be executed before any action, as below.
public class AuthorizationFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext filterContext)
{
}
}
If you can see in below image I can access route template from Quick Watch inside filter. But if I write same code, it throws an error 'System.Web.Http.WebHost.Routing.HttpWebRoute' is inaccessible due to its protection level
Is there any other way to access route template
Property Using : (((System.Web.Http.WebHost.Routing.HttpWebRoute)(HttpContext.Current.Request.RequestContext.RouteData.Route)).HttpRoute).RouteTemplate
This is how it will work.
public override void OnActionExecuting(HttpActionContext filterContext)
{
if (Settings.GetKeyValue<string>("EnableAuthorization") == "Enabled")
{
var routeTemplate = filterContext.Request.GetRouteData().Route.RouteTemplate;
}
}
I'm trying to build an implementation of the IHttpControllerActivator interface for with with StructureMap, so that I can resolve a dependency of a controller which takes a dependency on the HttpRequestMessage being processed in the MVC Web API pipeline.
My implementation of Create is as follows:
public IHttpController Create(
HttpRequestMessage request,
HttpControllerDescriptor controllerDescriptor,
Type controllerType)
{
return (IHttpController)this.Container
.With(request)
.With(controllerDescriptor)
.GetInstance(controllerType);
}
The Container property is a reference to the StructureMap IContainer instance passed to the activator when it is constructed.
My registration for the controllers uses reflection to obtain all the ApiController implementations:
foreach(var controller in this.GetType().Assembly.GetTypes()
.Where(type => typeof(ApiController).IsAssignableFrom(type)))
{
this.For(controller).Use(controller);
}
Using the debugger, I checked that initialises the controller instances and passes in their dependencies. However, when the ExecuteAsync method is called on the controller, an exception is thrown:
Cannot reuse an 'ApiController' instance. 'ApiController' has to be constructed per incoming message. Check your custom 'IHttpControllerActivator' and make sure that it will not manufacture the same instance.
After some digging and experimentation I discovered this is due to a check performed at the start of ExecuteAsync which checks the Request property of the ApiController to see if it has been assigned a value. If the property has a non-null value, it infers that the controller has already been used to process a request and aborts the operation.
Further to this, I verified that StructureMap attempted to use its setter-injection behaviour when composing the controller and is responsible for Request having a non-null value.
In my registry, I haven't configured any setter-injection, so I'm confused as to why it's being invoked here. A poke around the StructureMap API hasn't yielded any obvious answers as to how I could change the behaviour exhibited.
Am I invoking StructureMap incorrectly? Is there a configuration setting I can leverage to say "never ever assign a property value"?
I think your issue revolves around the way that you are setting up your controllers with StructureMap. In order to get this working correctly, the best way is to hook into the WebAPI stack's dependency injection stack by creating your own implementation of IDependencyResolver. There's a pretty good example of this at http://craigsdevspace.wordpress.com/2012/02/26/using-structuremap-with-web-api/
The basic code, though, might look something like:
IDependencyResolver:
public class _DependencyResolver : _DependencyScope, IDependencyResolver {
public _DependencyResolver(IContainer container) : base(container) { }
public IDependencyScope BeginScope() {
return new _DependencyScope(_container);
}
}
IDependencyScope:
public class _DependencyScope : ServiceLocatorImplBase, IDependencyScope {
protected readonly IContainer _container;
public _DependencyScope(IContainer container) {
if (container == null)
throw new ArgumentNullException("container");
_container = container;
}
public override object GetService(Type serviceType) {
if (serviceType == null)
return null;
try {
return (serviceType.IsAbstract || serviceType.IsInterface)
? _container.TryGetInstance(serviceType)
: _container.GetInstance(serviceType);
} catch {
return null;
}
}
protected override object DoGetInstance(Type serviceType, string key) {
if (string.IsNullOrEmpty(key))
return _container.TryGetInstance(serviceType);
return _container.TryGetInstance(serviceType, key);
}
protected override IEnumerable<object> DoGetAllInstances(Type serviceType) {
return _container.GetAllInstances<object>().Where(s => s.GetType() == serviceType);
}
public IEnumerable<object> GetServices(Type serviceType) {
return _container.GetAllInstances<object>().Where(s => s.GetType() == serviceType);
}
public void Dispose() {
//_container.Dispose();
}
}
To hook these classes up to WebAPI, then, you would add the following to Global.asax:
GlobalConfiguration.Configuration.DependencyResolver =
new _DependencyResolver(ObjectFactory.Container);
And either in Global.asax or in your Bootstrapper, you would add the following:
ObjectFactory.Initialize(x => {
x.Scan(scanner => scanner.AddAllTypesOf<ApiController>());
});
This sets up your StructureMap implementation to use the stack's pre-existing injection structure - which should avoid the problem that you're having.
I am trying to inject dependency to my session dictionary class into my controller's constructor. eg:
public AccountController(ISessionDictionary sessionDictionary)
{
this.sessionDictionary = sessionDictionary;
}
In my global.asax file:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders.Add(typeof(ISessionDictionary), new SessionDictionaryBinder());
}
My SessionDictionaryBinder:
public class SessionDictionaryBinder : IModelBinder
{
private const string sessionKey = "_seshDic";
public object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
if (bindingContext.Model != null)
{
throw new InvalidOperationException("Cannot update instances");
}
ISessionDictionary seshDic = (SessionDictionary)controllerContext.HttpContext.Session[sessionKey];
if (seshDic == null)
{
seshDic = new SessionDictionary();
controllerContext.HttpContext.Session[sessionKey] = seshDic;
}
return seshDic;
}
}
When I go to /account/login, I get the error:
Error activating ISessionDictionary
No matching bindings are available, and the type is not self-bindable.
Activation path:
2) Injection of dependency ISessionDictionary into parameter sessionDictionary of constructor of type AccountController
1) Request for AccountController
I am using Ninject for DI, and my other bindings in the file contained within the App_Start directory work fine. I am assuming the modelbinder should go into that file, but what is the syntax?
Cheers!
As I see it you are mixing things up a little bit.
Here you register your model binder to the MVC3 Framework:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders.Add(typeof(ISessionDictionary), new SessionDictionaryBinder());
}
Afther this registration you can write Controller actions expecting an ISessionDictionary instance, but that has nothing to do with controller constructors. Ninject doesn't know about your binding, so you have to include your binding in the Ninject module you are using (and if you don't have actions expecting an ISessionDictionary parameter, than you don't need the model binder at all)
I'm pretty new to MVC ASP.NET. I read about OnException override method. I'm thinking, whether I should put try catch {throw} on Controller or Model in order for OnException to be invoked. OR, I try catch not required, OnException will be invoked autmatically if any exception occurs?
Thanks Heaps.
"Called when an unhandled exception occurs in the action."
http://msdn.microsoft.com/en-us/library/system.web.mvc.controller.onexception.aspx
If you don't handle (i.e. "catch") an exception, the OnException method should be called.
I ended up doing this:
Created LogAndRedirectOnErrorAttribute class that uses abstract class FilterAttribute and implements IExceptionFilter as shown below:
public class LogAndRedirectOnErrorAttribute : FilterAttribute,IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
//Do logging here
Util.LogError(Utility.GetExceptionDetails(filterContext.Exception), TraceEventType.Critical.ToString());
//redirect to error handler
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(
new { controller = "Error", action = "Index" }));
// Stop any other exception handlers from running
filterContext.ExceptionHandled = true;
// CLear out anything already in the response
filterContext.HttpContext.Response.Clear();
}
}
And on Each Controller Class where necessary, use the above attribute:
[LogAndRedirectOnError]
public class AccountController:Controller
{
.....
}