How to gain control of what is returned after a route matches? - asp.net

With ASP.NET MVC, when a route matches, the framework will determine the Controller type and then use the ControllerActivator class to create a new instance of it and then execute the Action method and finally return it's result to the request caller.
Just out of curiosity, what if I wanted to intervene exactly between the route and the Controller. Let's say controllers don't fit my needs. Let's say I just need to execute a random method in a class and return it's result.
What would I do then? What would I have to override? Can you please provide the path? A sample code would be appreciated too.

Create your own controller factory which implements IController factory. Something like below.
public class MyControllerFactory : IControllerFactory
Implement IControllerFactory interface
Register your new controller factory in Global.asax Application_Start event.
ControllerBuilder.Current.SetControllerFactory(typeof(MyControllerFactory));
You can check code of DefaultControllerFactory as reference for implementing your own factory.

Related

Can I use controller name in controller destination

I want a route that will take requests from
/api/v1/job
to
Controller that lives in
/api/v1/jobController
where the controller name is jobv1Controller
configuration.Routes.MapHttpRoute(
"v1",
"Api/v1/{controller}/{id}",
new { controller = "{controller}v1", id = RouteParameter.Optional });
short version:
the in-built DefaultControllerFactory may not be able to create the controller you need, since it treats the value as a plain name string, and doesn't do any token replacement.
the solution would be to extend DefaultControllerFactory and override the CreateController method. Change the controllerName value and then use the base functionality to get you that controller.
Register your custome factory in Global.asax
ControllerBuilder.Current.SetControllerFactory(
typeof(YourCustomControllerFactory));
long version:
As you know the flow is as follows:
Request >> Routing System >> MVC's Default Controller Factory >> Create Controller >> Invoke it.
I don't think it is possible to give dynamic values in the default route data dictionary and expect the default controller factory to find that controller.
This is because the built-in controller factory works off the direct value of the controller key, given in the route data dictionary.
The MVC Handler does no magic there of trying to parse the controller value provided as some formatted string, and associating Url Fragment values (controller/action etc.) in this format. it sees it as a straight up value.
By default, the DefaultControllerFactory is invoked to get the controller type, and it uses the string value as-is to activate a controller type.
So one way to solve your problem is to define a custom factory implementing IControllerFactory
Once you do that, your factory's
CreateController method will be called, with the RequestContext and ControllerName string as the 2 parameters.
The RequestContext has the RequestContext.RouteData.Values dictionary, which has all the routing data, tokens, constraints, namespaces etc.
Once you have the incoming controller name, you can massage it to whatever format you need (controllername + "v1") and then instantiate that controller (using DI containers or Service Locator or Activator.CreateInstance etc. whatever you wish) and return it. Try to use some sort of look-up cache for this.
Once you have implemented your custom factory, you can register your custom controller factory with MVC as follows in Global.asax:
ControllerBuilder.Current.SetControllerFactory(
typeof(YourCustomControllerFactory));

Custom authorization in ASP.NET as filter or in controller's constructor?

In my ASP.NET Web API controller, I want to restrict access to those in the User role. The common way to do this is to extend the AuthorizeAttribute (example, example) and then sprinkle my controllers with my custom attribute (e.g. [AuthorizeUser]).
Another way to do this is to add a function in the controller's constructor. The constructor is required anyway because I'm using dependency injection.
Here's some code:
public class MyController: ApiController
{
private IUnitOfWork unitOfWork;
private IAccountUtils accountUtils;
// Constructor
public MyController(
IUnitOfWork unitOfWork,
IAccountUtils accountUtils)
{
this.unitOfWork = unitOfWork;
this.accountUtils = accountUtils;
// Restrict access to 'User' role
accountUtils.ThrowExceptionIfUserNotInRole(User.Identity, "User");
}
// More code
}
Because there are countless tutorial and examples of using a filter to authorize users I assumed that was the best way to go. However, when I stepped through my code in the debugger I found that the constructor method gets fired BEFORE the filter.
To optimize code, it makes sense to break as soon as possible if the user is not authorized to access the controller. If I'm not mistaken, then, it should be more efficient to perform authorization in the constructors instead of in a filter. Am I correct or am I missing something here?
It seems like your main concern is optimizing your code, and you're correct to note that the controller constructor runs before the authorization filter. But the difference in performance between those two solutions is extremely small and shouldn't really impact your service.
While throwing from a constructor might work, it's not the most elegant solution because it requires you to authorize in code rather than declaratively with an attribute. It also forces you to mix object instantiation logic with authorization logic which isn't as clean.
So I'd recommend just sticking to using an authorization filter for this one.

Manually doing what the ModelAttribute annotation does in Spring MVC

I have an action method on a Spring MVC controller that has an argument annotated with #ModelAttribute. However, I don't know at compile time what the type of this parameter will be - I know the abstract base type but not the derived type.
At runtime, I will be able to decide what class I am expecting and I will be able to get a new'd up instance of this class. However, I have no idea what code I should be calling to parse the request data in the same fashion that #ModelAttribute does.
I've looked around and it seems that if i can get a hold of a WebRequestDataBinder I can use that to populate my object, but for that I need a BinderFactory and this is where I kind of get lost.
Can anyone give me some pointers here - or tell me that I am looking at it the wrong way and need to do something else?
you can inject the model itself in your controllers method and access the attribute yourself.
#RequestMapping(...)
public void doStuff(ModelMap model) {
Object attr = model.get("nameOfAttribute");
// ...
}

HandlerMethod given a HttpRequest?

I have an interceptor in which i want to do some intercepting logic based on the annotation on a controller method (Not on controller class). Say want to restrict the access to that controller method for certain users only. Is there any way to get the Handler method (Yes not the handler class) in the HandlerInterceptor?
I'm afraid not. You would have to group the desired methods in one (or a few) classes and base your check on the class, rather than method.
I guess you can parse the annotations yourself and match the paths, or try to see what spring does to do so in its classes, but that would be more complicated and error-prone.
You can try (but I haven't used it, so I don't know if it works) the #Interceptors annotation on your methods (saw it here)
You can do this in Spring 3.1 now with something like this:
public class ApiSecurityInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HandlerMethod method = (HandlerMethod) handler;
Api methodAnnotation = method.getMethodAnnotation(Api.class);
if (methodAnnotation != null) {
// this method is an #Api, we check the credentials
// you can do other things with annotation parameters at this point too
}
}
}
Then map it in servlet-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
...
<mvc:interceptors>
<bean class="com.orderpipe.prototype.server.web.interceptors.ApiSecurityInterceptor"/>
</mvc:interceptors>
Then in your actual controller:
#Controller
#RequestMapping(value = "/api-service")
public class AccountApiController {
#Api(type=CredentialType.OAUTH)
#RequestMapping(value="get", method = RequestMethod.GET)
public String get(Model model) {
// secured method via oauth, for example
// in a simpler example, you'd not have the parameter for credential type.
}
}
I use it to implement special servlet paths that implement different security mechanisms to the normal app, for example /api uses oAuth credentials.
I have the same need.
I consider an inconsistency that Spring MVC promotes the use of controller methods to handle requests, but the HandlerInterceptor interface does not supply the handler method that's going to handle the request as a parameter; only the controller object.
Requests are handled at the method level and it's the method execution what you need to intercept and for doing that efficiently you need to gain access to the method meta-information, for example, custom annotations declared at method level or its arguments.
The HandlerInterceptor.preHandle signature shoud be:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handlerInstance, Method handlerMethod)
throws Exception;
So that you can do something like this:
hadlerMethod.getAnnotation(MyCustomAnnotation.class);
GOT IT?
In my case, I wanted to implement indexed-paremeter mapping; something STRIPES FRAMEWORK has (or flash scoping).
Do I have to resort to AspectJ to implement my cross-cutting functionality? DISSAPOINTING!
Firstly this is against MVC architectural pattern. MVC architecture is an architectural pattern that desires to
isolate "domain logic" (the application logic for the user) from the user interface (input and presentation), permitting independent development, testing and maintenance of each (separation of concerns).
See here
And controller has a great work in it.It desires decoupling, focusing on design porpose, and etc. I hope software developers don't give up GRASP :/

In asp.net mvc is it possible to make a generic controller?

I'm attempting to create a generic controller, ie:
public class MyController<T> : Controller where T : SomeType
{ ... }
However, when I try to use it, I'm running into this error everywhere...
Controller name must end in 'Controller'
So, my question, Is it possible to make a generic controller in asp.net mvc?
Thanks!
If I understand you properly, what you are trying to do, is route all requests for a given Model through a generic controller of type T.
You would like the T to vary based on the Model requested.
You would like /Product/Index to trigger MyController<Product>.Index()
This can be accomplished by writing your own IControllerFactory and implementing the CreateController method like this:
public IController CreateController(RequestContext requestContext, string controllerName)
{
Type controllerType = Type.GetType("MyController")
.MakeGenericType(Type.GetType(controllerName));
return Activator.CreateInstance(controllerType) as IController;
}
Yes you can, it's fine and I've used them lots myself.
What you need to ensure is that when you inherit from MyController you still end the type name with controller:
public class FooController : MyController<Foo>
{
...
}
The default controller factory uses "convention" around controller names when it's trying to find a controller to dispatch the request to. You could override this lookup functionality if you wanted, which could then allow your generic controller to work.
This MSDN article...
http://msdn.microsoft.com/en-us/magazine/dd695917.aspx
... has a good writeup of what's going on.
This is a duplicate of asp.net mvc generic controller which actually contains the correct answer. Jeff Fritz's answer is absolutely not correct. Creating your own IControllerFactory will not get past the limitation in ExpressionHelper.GetRouteValuesFromExpression which is generating the error you are seeing. Implementing your own IControllerFactory will still leave you with errors whenever you call RedirectToAction, BuildUrlFromExpression, ActionLink, RenderAction, BeginForm, any any methods that call those.
What is interesting to me, is that Microsoft's "restriction by convention" is already enforced by the constraint "where TController : Controller" that is placed upon the type in the ExpressionHelper.GetRouteValuesFromExpression method. No generic will ever satisfy the convention validation:
string controllerName = typeof(TController).Name;
if (!controllerName.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)) {
throw new ArgumentException(MvcResources.ExpressionHelper_TargetMustEndInController, "action");
}
unless it is inherited by a class ending in "Controller" because typeof(AnyGeneric).Name will never end with "Controller".
If i was you, i'd get the MVC source and create a test MVC project with the source code so you can examine where the exception is generated and see what you can do about your generic idea and the enforced "*controller" naming convention.

Resources