How can I load multiple controller factories and pass control on to the next one? - asp.net-mvc-3

I've created a generic controller factory to load entities from the database by parsing out the url:
entity/products/123456.htm
However, I'd like to be able to load an actual controller if the entity is not found, or to override the default entity behavior if necessary by creating a physical controller, instead of a "virtual" one created by the URL pattern.
Right now, in global.asax.cs I'm doing:
ControllerBuilder.Current.SetControllerFactory(typeof(EntityControllerFactory));
How can I, either in EntityControllerFactory, or here in global.asax.cs, pass control on to another factory, in the event that I'd like MVC's default controller/action scheme to take over?

You could create a composite IControllerFactory implementation:
public class EntityControllerFactory : IControllerFactory {
private IControllerFactory defaultFactory = new DefaultControllerFactory();
public IController CreateController(RequestContext requestContext, string controllerName) {
if(needsCustomLogic) {
// do your custom logic here and return appropriate result
} else {
return defaultFactory.CreateController(requestContext, controllerName);
}
}
// same for the other methods on IControllerFactory
}
This works because by default the value of ControllerBuilder.Current.GetControllerFactory() is an instance of DefaultControllerFactory.
You might also consider making your factory more future-proof (in case a new version of MVC starts returning a different type from GetControllerFactory; unlikely but it could happen) by getting the default instance and passing it into your factory:
// in Global.asax
var defaultFactory = ControllerBuilder.Current.GetControllerFactory();
ControllerBuilder.Current.SetFactory(new EntityControllerFactory(defaultFactory));

Related

Duplicate RequestMapping

I'm working on an open source named OpenMRS supporting Spring MVC. I cannot modify core source for update purpose later. So I must write a module, something like plugin to add functions to the system. The problem is that I want to alter the original screen to mine by using portlet to redirect to my jsp. The controller of the core code is something like this:
#RequestMapping("/patientDashboard.form")
protected String renderDashboard(#RequestParam(required = true, value = "patientId") Integer patientId, ModelMap map){
....
return "patientDashboardForm";
}
I'm not familiar with Spring but as I know that when the url ends with /patientDashboard.form?patientId=xxx the function will call patientDashboardForm.jsp. Now I want to return to my jsp so I must define a new class with same code but return to my jsp (to do this because cannot modify the core code). But by defining same mapping /patientDashboard.form causes error "Cannot map handler XXX to URL path /patientDashboard.form: There is already handler YYY mapped".
So is there anyway to overcome this situation ?
There is no way to overrule an existing #RequestMapping. Each mapping must be unique. What you could do is the following. Instead of adding a request parameter, add a path parameter like this
#RequestMapping("/patientDashboard.form/{patientId}", method = RequestMethod.GET)
public String renderDashboard(#PathVariable("patientId") final long id, Model model) {
/* your code here */
}
This will create a new #RequestMapping that will differ from the existing one.
You have to create another #Controller extending the existing one. Then, you can define your custom mappings (you can't reuse the existing one) and reimplement the superclass methods at your convenience, redirecting to your view and defining custom logic there.
Example:
#Controller
#RequestMapping("/your_new_mapping")
public class YourController extends BaseController {
#Override
#RequestMapping("/patientDashboard.form")
public void renderDashboard(#RequestParam(required = true, value = "patientId") Integer patientId, ModelMap map){
// Call to default functionallity
super.renderDashboard(patientId, map);
...
// your custom code here
return "yourCustomJSPHere";
}
}

Property Injection into Web API's `System.Web.Http.Filters.ActionFilterAttribute`

Where is the recommended place to perform property injection into action filter attributes in an ASP.NET web api project? In MVC 3 land, we could set our own implementation for ControllerActionInvoker at the point of resolving our controllers from our IoC container, and override its GetFilters() method to inject components resolved from the container.
Is there a similar place to do this in an ASP.NET Web API project? I have a controller factory that resolves controllers from the container, with the CreateController method as so:
public IHttpController CreateController(HttpControllerContext controllerContext, string controllerName)
{
var controller = _kernel.Resolve<IHttpController>(controllerName);
controllerContext.Controller = controller;
controllerContext.ControllerDescriptor = new HttpControllerDescriptor(_configuration, controllerName, controller.GetType());
return controllerContext.Controller;
}
I've had a look at HttpControllerDescriptor to see if there is somewhere to do the injection, but I can't see a suitable place. Any pointers in the right direction?
You need to implement IHttpControllerSelector and register your selector in the (Services property) DefaultServices of the HttpConfiguration.
Or alternatively, to use your own resolver/DI framework, you need to replace the resolver. See here for an example.
You need to Implement your own IFilterProvider. Have a look at the source for ActionDescriptorFilterProvider. This is where you can inject properties.
Here is ActionDescriptorFilterProvider implementation:
public IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor)
{
if (configuration == null)
{
throw Error.ArgumentNull("configuration");
}
if (actionDescriptor == null)
{
throw Error.ArgumentNull("actionDescriptor");
}
IEnumerable<FilterInfo> controllerFilters = actionDescriptor.ControllerDescriptor.GetFilters().Select(instance => new FilterInfo(instance, FilterScope.Controller));
IEnumerable<FilterInfo> actionFilters = actionDescriptor.GetFilters().Select(instance => new FilterInfo(instance, FilterScope.Action));
return controllerFilters.Concat(actionFilters);
}
All you have to do is to use instance lambda parameter and inject properties.
Registration As you have figured out, the filter provider needs to be registered against the HttpConfiguration. Or alternatively, to use your own resolver/DI framework, you need to replace the resolver. See here for an example.

Constructor injection of a View Model instance used as an Action method parameter

When a view model is created you can populate the options (e.g. used in a dropdown list) into a setter property of the view model.
The problem is that when that view model is later passed as a parameter (by the framework!) into an action method, those property values has not become automagically
repopulated, so if you need to redisplay the form because of validation errors, you need to repopulate those options again.
One potential solution, which I am asking for specifically in this question, is how to make the MVC framework instantiate the view model with constructor injection, which would provide the view model constructor with an implementation of some kind of data access object (e.g. a repository) that can be used for retrieving the options when they are requested by the view (e.g. in the helper method "DropDownListFor") ?
I think the solution might have something to do with implementations of IModelBinderProvider or IModelBinder but after having experimented with these things from example code snippets here and there on the net, I am still looking for a completely working example, with downloadable executable code without any missing piece of how putting all things together.
If you are looking for some alternative discussion about how to populate a select list, e.g. with "Dependecy Lookup" instead of "Dependecy Injection" you may want to check out the following discussion:
Best way to populate SelectList for ViewModel on GET/POST
Best way to populate SelectList for ViewModel on GET/POST
Some days ago I wrote the following follow-up-question in that thread about the "Dependecy Injection" I am now looking for in this thread:
https://stackoverflow.com/a/8674525/310457
(which provides a code example about the problem I am looking for a solution of)
But instead of hoping that someone will find that old thread with a less specific title, I have created this new question with a more specific subject about what I am looking for.
And I will also provide a link from that thread into this new question for anyone that want to follow-up regarding this specific solution I am looking for.
I'm assuming you want to have your ViewModels automatically injected with something via their Constructor - for example some kind of configuration object that the View will use to determine what to show. I'm also assuming that this approach is causing a "No parameterless constructor defined for this object" error when MVC tries to automatically create and bind a model instance, from the arguments of your Controller Action. Let's also then assume that we will use a DI framework to inject the SiteConfig object into our Controllers automatically at runtime.
This means that the only problem we have to solve is how to get the injected object from our Controller into its Actions' ViewModels when they are automatically bound.
So let's define a base model for others to inherit from.
BaseViewModel
public class BaseViewModel
{
public ISiteConfig SiteConfig { get; set; }
public BaseViewModel(ISiteConfig siteConfig)
{
this.SiteConfig = siteConfig;
}
}
And now let's create a model that inherits from it.
IndexViewModel
public class IndexViewModel : BaseViewModel
{
public string SomeIndexProperty { get; set; }
public IndexViewModel (ISiteConfig siteConfig) : base(siteConfig) {}
}
And now let's define a Base Controller that our Controllers will inherit from.
BaseController
public abstract class BaseController : Controller
{
protected BaseController(ISiteConfig siteConfig)
{
_siteConfig = siteConfig;
}
private readonly ISiteConfig _siteConfig;
public ISiteConfig SiteConfig
{
get
{
return _siteConfig;
}
}
}
Now we define our actual controller.
HomeController
public HomeController: BaseController
{
public HomeController(ISiteConfig siteConfig): base(siteConfig) {}
}
Assuming we're using Ninject for DI, Ninject would be configured to automatically create the Controller and pass a concrete ISiteConfig object into its Constructor at runtime.
Now we add our Action to the Controller.
Index Action
public ActionResult Index(IndexViewModel model)
{
return View(model);
}
And so this is the point where without doing anything else, MVC will explode with a "Parameterless Constructor" error if you try to call the Index Action, because MVC can't find a ViewModel constructor that takes no arguments.
And so, the answer. We need to override the default ModelBinder.
BaseViewModelBinder
public class BaseViewModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
if (modelType == typeof(BaseViewModel) || modelType.IsSubclassOf(typeof(BaseViewModel)))
{
var baseControl = controllerContext.Controller as BaseController;
if (baseControl == null)
{
throw new Exception("The Controller must derive from BaseController");
}
var instance = Activator.CreateInstance(modelType, baseControl.SiteConfig);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => instance, modelType);
return instance;
}
else
{
return base.CreateModel(controllerContext, bindingContext, modelType);
}
}
}
And we need to set this as the default model binder in global.asax.cs :
protected void Application_Start()
{
...
ModelBinders.Binders.DefaultBinder = new BaseViewModelBinder();
}
That's all. As you can see, when you view the Index Action now, MVC will use our custom model binder. It will realise that the IndexViewModel derives from BaseViewModel, and so will attempt to spin up an IndexViewModel instance using the ISiteConfig it can find in the Action's Controller (because the Controller derives from BaseController).

How model annotated methods should interact?

I would like to know how controller methods should interact with ModelAttribute annotated methods.
For example handlePage method would like to filter the list created by createList method?
Or set the id for the object created by createAnObject method?
Is it possible or ModelAttribute annotated methods are designed to attach static data to the model?
#ModelAttribute("someList")
public ArrayList<SomeList> createList() {
return new ArrayList<SomeList>(100);
}
#ModelAttribute("anObject")
public AnObject createAnObject() {
return new MyObject();
}
#RequestMapping(method=RequestMethod.GET)
public void handlePage(Model model) {
//Do some stuff to populate the model....
}
The two shouldn't really interact. #ModelAttribute, in this context, is intended for exposure of reference data, i.e. data that doesn't depend on the details of the request.
If your handler method needs to modify that data, then #ModelAttribute isn't appropriate. Instead, the handler method should explicitly add the data to the model after modifying it.

MVC - Interface as Controller Action parameter

I want to pass one of a number of classes that implement an interface from my view back to my controller action. I use an ActionLink in my view passing the instance to my action, but it naturally fails because MVC cannot deal with interfaces via default model binding.
So :
<%=Html.ActionLink(flow.Source.Name, "Get", new {container=flow.Source})%>
is in a loop and each flow.Source conforms to IContainer.
public class Flow
{
public virtual IContainer Source { get; private set; }
}
public interface IContainer
{
//members here
}
public class File : IContainer
{}
public class Worksheet : IContainer
{}
Basically I want to call an action method :
public ActionResult Get(IContainer container)
{
// Do something
}
The reason being that I need to retrieve the state of the current container passed to my action method from the database. I use NHibernate and have entities mapped on a table per entity, so have one for File and one for Worksheet for example, so need to able to decide which data access class to use. Make sense? Probably not!
Can this be done without moving towards a base class Container? Can I stick with an interface being passed to my action method and resolve the subtype instance passed in place of the interface?
Any help with this would be gratefully appreciated.
An interface needs 'some' concrete implementation to reference when you would call your class. I think judging by your post you are aware of this : )
With that said there is 'kinda' of an approach handled here where you just create your own model binder that has to know about (or how) to map to and create a concrete type (either directly or by dependency injection)
ASP.NET MVC - Custom Model Binder on Interface Type

Resources