I have two checkboxes in my MVC app which are both boolean / bit fields. "NotifyEmail" & "NotifySMS".
Whenever I post back to the server and an error occurs, the state of the checkbox is gone event though I set attempted values.
Why not something as simple as this?
<%=Html.CheckBox("AgreeToRules", (Request.Form["AgreeToRules"] ?? string.Empty).Contains("true"))%>
Update: This is fixed in RC2.
This question together with this one,
Html.Checkbox does not preserve its
state in ASP.net MVC,
addresses a very undocumented feature of the ASPNET.MVC RC1. I have been searching around for hours to find a good answer, but there are very few to find.
There is a bug, apparently, which prohibit checkboxes and radiobuttons to maintain their state from ModelState. As we also know by now, is that these two controls are handled specially by the Html helpers.
The best I managed to come up with, was to build my own ViewBinder:
From a very simple view:
<h2>Keep checkbox value between posts</h2>
<% using (Html.BeginForm("update", "checkbox")) {%>
<p><%= Html.CheckBox("a") %></p>
<p><%= Html.CheckBox("b") %></p>
<p><%= Html.TextBox("dummy") %></p>
<input type="submit" value="update" />
<% } %>
Associated with an equally simple controller:
public class CheckboxController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Update()
{
var binder = new ViewBinder(ViewData, ValueProvider);
binder.UpdateBooleanValues("a", "b");
binder.UpdateMissingValues();
return View("Index");
}
}
And a simple class to make it all work:
internal class ViewBinder
{
private readonly IDictionary<string, ValueProviderResult> valueProvider;
private readonly ViewDataDictionary viewData;
public ViewBinder(ViewDataDictionary viewData, IDictionary<string, ValueProviderResult> valueProvider)
{
this.valueProvider = valueProvider;
this.viewData = viewData;
}
public void UpdateMissingValues()
{
foreach (var key in valueProvider.Keys)
{
if (ValueIsMissing(key)) UpdateValue(key);
}
}
public void UpdateBooleanValues(params string[] names)
{
foreach (var name in names)
{
UpdateValue(name, BooleanValueFor(name));
}
}
private bool BooleanValueFor(string name)
{
return valueProvider[name].AttemptedValue != "false";
}
private bool ValueIsMissing(string key)
{
return viewData.ContainsKey(key) == false;
}
private void UpdateValue(string key)
{
var value = valueProvider[key].AttemptedValue;
UpdateValue(key, value);
}
private void UpdateValue(string key, object value)
{
viewData[key] = value;
}
}
MVC does not have ViewState like WebForms does - this means that you now have the responsibility of maintaining those values.
This will require that you store whether or not the checkbox was checked and then applying that setting to the checkbox again before the page is rendered to the browser in your View.
Adam,
Assuming you understand that MVC does not include server functionality to handle Asp.Net post-backs, If you need to send a message back to the server that informs your application that the check box was checked, then it's probably best to do that with Javascript and an Ajax request. .Net MVC includes a the JQuery Javascript library so doing this may be easier then you think. Here's an SO post that kind of covers how to use checkboxes correctly in MVC.
Otherwise, realize that MVC doesn't support post-back, and like Andrew said above, doesn't support Asp.Net view-state either. However, you could go back to the old school way of view-state and use a regular HTML hidden input element with a little bit of javascript to maintain your state.
That all being said, you might want to take a minute to read this article. A lot of MVC frameworks assume that you will be using the Post -> Redirect -> Get pattern for handling user input in your web forms. If you continue to use your current pattern of post-back and view state, you may run into more problems in the future like the one you're currently trying to solve.
How are you specifying your checkbox HTML? Binding will require a hidden input element in addition to the checkbox input element. Html.Checkbox will handle this for you, or you can study how it does it and do it yourself.
Using an HTML Helper such as Html.CheckBox will persist the state automatically on POST.
Andrei Rinea is partially right. But I have done - is use the helpers and pass back into the page the previous values into the DataClass (accessed by Model. etc). It works well.
Others may find this solution useful:
Maintain state of a dynamic list of checkboxes in ASP.NET MVC
Related
A problem I come up against again and again is handling redirection to the previous page after a user runs some action such as clicking a 'Back To ...' link or saving the record they are editing.
Previously whenever I have needed to know what page to return to, I would provide a returnURL parameter to my current view.
http://blah.com/account/edit/1?returnURL="account/index"
This isn't a very clean way of handling this situation, as sometimes the return URL contains parameters such as search strings, etc, which have to be included in the URL.
http://blah.com/account/edit/1?returnURL="account/index?search="searchTerm""
Also, this creates an issue when a user can go another page forward before coming back to the page with the returnURL because you have to pass the returnURL through all visited pages.
Simply calling the browser's Back functionality isn't really sufficient either, because you might want the page to refresh, e.g. to show the edits you just saved in the previous page.
So my question is, has anyone found a smart way to handle this kind of situation, specifically in an MVC environment?
Note: I am using ASP .NET MVC so if possible I'd like answers to pertain to that, however any ideas are welcome.
What's wrong with setting a cookie, or using a session variable? The only reason you wouldn't is if you don't control the page that calls into you, in which case your only options are query strings, post values, or referrer.
I thought I might add my answer to the question to see if others think it's a good idea.
I'm simply passing it through to the controller using TempViewData:
#{
TempData["returnURL"] = Request.Url.AbsoluteUri;
}
and then accessing it in a similar way to this (in my real version I check that the key is in TempData and that the returnURL is a real URL):
return Redirect(TempData["returnURL"].ToString());
If it needs to continue on past the first page change (i.e. Search page -> Edit page -> Edit Section page) I'm adding it again
TempData["returnURL"] = TempData["returnURL"];
Check my blog post on it: Using cookies to control return page after login on asp.net mvc 3
Just like #Mystere Man mentioned, you can just use a cookie or session for it. I went for cookies back when I had a similar situation a while ago.
Try register a new route of which the url is /{controller}/{action}/{id}/returnurl/{*url} and then use a RedirectToAction in the action that accepts url as a parameter
Request.UrlReferrer.AbsoluteUri
though i'd still argue that you shouldn't be creating your own "back" button.
Use an interceptor or an aspect:
Intercept each request in some fashion (e.g., a #Before aspect) and save the requested URL to the session, overwriting it each time
In your view layer, access that Session object as needed, in your case for the back link.
This kind of design allows you to always have the most recent request available if you want to use it. Here's an example to write an aspect / interceptor in .NET. Additionaly, PostSharp is a .NET aspect project.
At present, a quick and dirty method has eluded me... so I'm using a practical method.
On a conceptual level, the 'back-ability' of a page should be determined by the page that you're currently on. The View can infer this (in most cases) if the parameters captured in the Controller are passed to it via the ViewModel.
Example:
Having visited Foo, I'm going to Bar to view some stuff, and the back button should return to Foo.
Controller
public ActionResult Foo(string fooId) // using a string for your Id, good idea; Encryption, even better.
{
FooModel model = new FooModel() { fooId = fooId }; // property is passed to the Model - important.
model.Fill();
return View("FooView", model);
}
public ActionResult Bar(string fooId, string barId)
{
BarModel model = new BarModel() { fooId = fooId; barId = barId };
model.Fill()
return View("BarView", model)
}
ViewModels
public class FooModel
{
public string fooId { get; set; }
public void Fill()
{
// Get info from Repository.
}
}
public class BarModel
{
public string fooId { get; set; }
public string barId { get; set; }
public void Fill()
{
// Get info from Repository.
}
}
View (Partial) // No pun intended... or maybe it was. :)
Your BarView can now interpret from its model where it needs to go back to (using fooId).
On your BarView (using MVC2 syntax):
Back
You can use Html.ActionLink as well.
Alternatively:
You can inherit your ViewModels from a BaseViewModel, which can have a protected property returnURL. Set this where necessary.
Example:
On your ViewModel:
public class BarModel : BaseViewModel
{
public string fooId { get; set; }
public string barId { get; set; }
public void Fill()
{
returnURL = string.Format("/Foo?fooId={0}", fooId)
// Get info from Repository.
}
}
On View:
Back
Would this be better handled by partial actions that display without leaving the page and using JQuery to make a dialog/wizard workflow?
Then you only need to react to the 'Finish' button on the dialog to refresh the original view.
For the part of your question regarding "saving the record they are editing" I would think the post-redirect-get (PGR) pattern would apply to you.
This might be a good place to read about it if you are not familiar with it.
http://en.wikipedia.org/wiki/Post/Redirect/Get
http://blog.andreloker.de/post/2008/06/Post-Redirect-Get.aspx
Encode the returnUrl using Url.Encode(returnUrl) for inclusion in the URL.
When ready to redirect, use Url.Decode(returnUrl) and use the value for the actual redirect.
Which section of ASP.NET MVC should be overrided to be able to change the name of fields (Model Properties) in output to a custom things? Something like below:
<input id="IsActive" name="IsActive" type="checkbox" />
to this:
<input id="MYCUSTOMFORMAT-IsActive" name="MYCUSTOMFORMAT-IsActive" type="checkbox" />
This custom formatting shouldn't break down anything such client-side and server-side validation.
Thanks in advance ;)
More Info
I know that we can do this in Display/Editor Templates but i think this will cause infringement.
You can override the name in the HtmlAttributes parameter of the Html.TextBoxFor (etc) helper methods - such as:
#Html.TextBoxFor(o=>o.FirstName, new {id = "customId_originalId"})
However since you are changing this on the client side, the server side will not be able to recognize these changed names and will not bind properly unless you write your own model binder. As such it probably isn't aware of the server side validations to link this to either so again you are stuck handling this in a custom rolled manner.
A simple workaround for this if you want a constant prefix, but not necessarily the right way to do things, would be to use a viewmodel that contains your properties. in this case:
public class CustomViewModel
{
public bool IsActive {get;set;}
}
[HttpGet]
public ActionResult MyView()
{
CustomViewModel MYCUSTOMFORMAT = new CustomViewModel();
return View(MYCUSTOMFORMAT);
}
[HttpPost]
public ActionResult MyView(CustomViewModel MYCUSTOMFORMAT){
return View(MYCUSTOMFORMAT);
}
This will give you an Id of MYCUSTOMFORMAT.IsActive.
The proper way to do this would likely be overriding the default model binder and how it handles translating names to properties but I don't know model binders well enough to give you much direction on this.
I have a view model like such:
public class MyViewModel
{
public string Name { get; set; }
public List<Purchases> Purchases { get; set; }
}
This viewmodel is sent to a view that allows the user to edit the name property. The Purchases property is used only to create a dropdown box for it:
<%: Html.DropDownListFor(t => t.Name, new SelectList(Model.Purchases, "Value", "Text")) %></p>
This works fine.
However, when I perform server-side validation and then return to the View, I'm getting an object null reference error because the Purchases property is now set to null. I'm guessing this is because when the form is submitted because the Purchases property isn't bound to any editable control, it isn't being passed back with the viewmodel.
How can I prevent this happening? I want to send back the List to be send back with the Post request always.
You don't need to send back the list. If validation fails then simply rebuild the view model from scratch. One of the main selling points of MVC is how well it works in a stateless environment. Web Forms used ViewState to do this kind of thing, I don't think you want to replicate this kind of functionality though.
I like to have two overloaded Action methods for this (both with the same name but different method signatures). One with an [HttpGet()] attribute and the other with an [HttpPost()]. If your model is found to be invalid on the POST then simply return the "GET" method (NOTE: you'll need to to pass in any parameters required to rebuild the view).
When I say return, I mean:
return MyGetAction();
and not a Redirect to the GET action.
If the model is valid then you could/should perform a RedirectToAction() to a GET Action (this means if the user hits the refresh button it won't submit the form again, this is called the Post/Redirect/Get (PRG) pattern)
You'd have to create a hidden input for each of the elements in the list in addition to the select list. Having said, that I think caching the results of the query on the server is a better way to handle repopulating the list if you don't want to perform the query again. There's no sense in sending the data back across the wire if the server can just hang on to it. Personally, I wouldn't even bother with the caching unless it proved to be a performance bottleneck. Just populate the model selection list from the DB.
<% for (int i = 0; i < Model.Purchases.Length; ++i) { %>
<%: Html.Hidden( string.Format( "Purchases[{0}]", i ), Model.Purchases[i] ) %>
<% } %>
Lee Gunn is spot on. To make the answer a little more concrete, it is very common to re-build non-scalar values in the event ModelState is not valid. This can be done by simply returning the [HttpGet] version in your Controller. However, you could simply re-build the purchases collection manually. It's up to you.
[HttpGet]
public ActionResult MyView(string name)
{
//get entity and build up a view model
var entity = _myDb.GetEntity(name);
MyViewModel vm = AutoMapper.Map<Entity, MyViewModel>(entity);
return vm;
}
[HttpPost]
public ActionResult MyView(MyViewModel vm)
{
If(!ModelState.IsValid)
{
//here is one way of doing it
return MyView("");
//OR
vm.Purchases = GetSomePurchasesBro();
return View(vm);
}
//continue on persisting and doing the Post Redirect Get
}
P.S.
Calling
return MyView("");
can be replaced with
return MyView(vm.Name);
Both will do the same thing (provided you're using the Html Helper Extensions, i.e. Html.TextBoxFor(x=>x.Name))
Defaut model binding looks in the ModelState for attemptedValues when rendering Html. This is described here by Steve Sanderson.
I'm trying to display a view model using an editor template that wraps the model in a fieldset before applying a base Object editor template.
My view:
#model Mvc3VanillaApplication.Models.ContactModel
#using (Html.BeginForm())
{
#Html.EditorForModel("Fieldset")
}
Uses a fieldset template (Views/Shared/EditorTemplates/Fieldset.cshtml):
<fieldset>
<legend>#ViewData.ModelMetadata.DisplayName</legend>
#Html.EditorForModel()
</fieldset>
Which in turn uses a basic template for all objects (Views/Shared/EditorTemplates/Object.cshtml):
#foreach (var prop in ViewData.ModelMetadata.Properties.Where(x =>
x.ShowForEdit && !x.IsComplexType && !ViewData.TemplateInfo.Visited(x)))
{
#Html.Label(prop.PropertyName, prop.DisplayName)
#Html.Editor(prop.PropertyName)
}
That's my intent anyway. The problem is that while the page renders with a fieldset and a legend, the Object template isn't applied so no input controls are displayed.
If I change the view to not specify the "Fieldset" template then my model's properties are rendered using the Object template, so it's not that my Object template can't be found.
Is it possible to pass the same model through multiple templates?
For what it's worth, the view model looks like this:
namespace Mvc3VanillaApplication.Models
{
[System.ComponentModel.DisplayName("Contact Info")]
public class ContactModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
I implemented what you have, and was able to reproduce it. I set a break point in Object.cshtml so I could inspect it and I was caught off guard to realize that it wasn't even hitting the object template when the fieldset template was being used. Then I stepped through the fieldset template and saw it was calling the template just fine, so something must be happening in the code which prevents it from displaying the object template.
I opened up the MVC3 source code, searched for EditorForModel and found the correct function.
public static MvcHtmlString EditorForModel(this HtmlHelper html) {
return MvcHtmlString.Create(TemplateHelpers.TemplateHelper(html, html.ViewData.ModelMetadata, String.Empty, null /* templateName */, DataBoundControlMode.Edit, null /* additionalViewData */));
}
Obviously this wasn't it, so I pressed F12 on TemplateHelpers.TemplateHelper, and once there again I pressed F12 on single line call which brings you to the meat of the function. Here I found this short bit of code starting on line 214 of TemplateHelpers.cs:
// Normally this shouldn't happen, unless someone writes their own custom Object templates which
// don't check to make sure that the object hasn't already been displayed
object visitedObjectsKey = metadata.Model ?? metadata.RealModelType;
if (html.ViewDataContainer.ViewData.TemplateInfo.VisitedObjects.Contains(visitedObjectsKey)) { // DDB #224750
return String.Empty;
}
Those comments are actually in the code, and here we have the answer to your question: Can one model be passed through multiple editor templates?, the answer is no*.
That being said, this seems like a very reasonable use case for such a feature, so finding an alternative is probably worth the effort. I suspected a templated razor delegate would solve this wrapping functionality, so I tried it out.
#{
Func<dynamic, object> fieldset = #<fieldset><legend>#ViewData.ModelMetadata.DisplayName</legend>#Html.EditorForModel()</fieldset>;
}
#using (Html.BeginForm())
{
//#Html.EditorForModel("Fieldset")
//#Html.EditorForModel()
#fieldset(Model)
}
And viola! It worked! I'll leave it up to you to implement this as an extension (and much more reusable) method. Here is a short blog post about templated razor delegates.
* Technically you could rewrite this function and compile your own version of MVC3, but it's probably more trouble than it's worth. We tried to do this on the careers project when we found out that the Html.ActionLink function is quite slow when you have a few hundred routes defined. There is a signing issue with the rest of the libraries which we decided was not worth our time to work through now and maintain for future releases of MVC.
In first cshtml template we can recreate ViewData.TemplateInfo (and clear VisitedObjects list)
var templateInfo = ViewData.TemplateInfo;
ViewData.TemplateInfo = new TemplateInfo
{
HtmlFieldPrefix = templateInfo.HtmlFieldPrefix,
FormattedModelValue = templateInfo.FormattedModelValue
};
now we can call another template with same model
#Html.DisplayForModel("SecondTemplate")
When I use the default model binding to bind form parameters to a complex object which is a parameter to an action, the framework remembers the values passed to the first request, meaning that any subsequent request to that action gets the same data as the first. The parameter values and validation state are persisted between unrelated web requests.
Here is my controller code (service represents access to the back end of the app):
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Create()
{
return View(RunTime.Default);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(RunTime newRunTime)
{
if (ModelState.IsValid)
{
service.CreateNewRun(newRunTime);
TempData["Message"] = "New run created";
return RedirectToAction("index");
}
return View(newRunTime);
}
My .aspx view (strongly typed as ViewPage<RunTime>) contains directives like:
<%= Html.TextBox("newRunTime.Time", ViewData.Model.Time) %>
This uses the DefaultModelBinder class, which is meant to autobind my model's properties.
I hit the page, enter valid data (e.g. time = 1). The app correctly saves the new object with time = 1. I then hit it again, enter different valid data (e.g. time = 2). However the data that gets saved is the original (e.g. time = 1). This also affects validation, so if my original data was invalid, then all data I enter in the future is considered invalid. Restarting IIS or rebuilding my code flushes the persisted state.
I can fix the problem by writing my own hard-coded model binder, a basic naive example of which is shown below.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([ModelBinder(typeof (RunTimeBinder))] RunTime newRunTime)
{
if (ModelState.IsValid)
{
service.CreateNewRun(newRunTime);
TempData["Message"] = "New run created";
return RedirectToAction("index");
}
return View(newRunTime);
}
internal class RunTimeBinder : DefaultModelBinder
{
public override ModelBinderResult BindModel(ModelBindingContext bindingContext)
{
// Without this line, failed validation state persists between requests
bindingContext.ModelState.Clear();
double time = 0;
try
{
time = Convert.ToDouble(bindingContext.HttpContext.Request[bindingContext.ModelName + ".Time"]);
}
catch (FormatException)
{
bindingContext.ModelState.AddModelError(bindingContext.ModelName + ".Time", bindingContext.HttpContext.Request[bindingContext.ModelName + ".Time"] + "is not a valid number");
}
var model = new RunTime(time);
return new ModelBinderResult(model);
}
}
Am I missing something? I don't think it's a browser session problem as I can reproduce the problem if the first data is entered in one browser and the second in another.
It turns out that the problem was that my controllers were being reused between calls. One of the details I chose to omit from my original post is that I am using the Castle.Windsor container to create my controllers. I had failed to mark my controller with the Transient lifestyle, so I was getting the same instance back on each request. Thus the context being used by the binder was being re-used and of course it contained stale data.
I discovered the problem while carefully analysing the difference between Eilon's code and mine, eliminating all other possibilities. As the Castle documentation says, this is a "terrible mistake"! Let this be a warning to others!
Thanks for your response Eilon - sorry to take up your time.
I tried to reproduce this problem but I'm not seeing that same behavior. I created almost exactly the same controller and views that you have (with some assumptions) and every time I created a new "RunTime" I put its value in TempData and sent it off through the Redirect. Then on the target page I grabbed the value and it was always the value I typed in on that request - never a stale value.
Here's my Controller:
public class HomeController : Controller {
public ActionResult Index() {
ViewData["Title"] = "Home Page";
string message = "Welcome: " + TempData["Message"];
if (TempData.ContainsKey("value")) {
int theValue = (int)TempData["value"];
message += " " + theValue.ToString();
}
ViewData["Message"] = message;
return View();
}
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Create() {
return View(RunTime.Default);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(RunTime newRunTime) {
if (ModelState.IsValid) {
//service.CreateNewRun(newRunTime);
TempData["Message"] = "New run created";
TempData["value"] = newRunTime.TheValue;
return RedirectToAction("index");
}
return View(newRunTime);
}
}
And here's my View (Create.aspx):
<% using (Html.BeginForm()) { %>
<%= Html.TextBox("newRunTime.TheValue", ViewData.Model.TheValue) %>
<input type="submit" value="Save" />
<% } %>
Also, I wasn't sure what the "RunTime" type looked like, so I made this one:
public class RunTime {
public static readonly RunTime Default = new RunTime(-1);
public RunTime() {
}
public RunTime(int theValue) {
TheValue = theValue;
}
public int TheValue {
get;
set;
}
}
Is it possible that your implementation of RunTime includes some static values or something?
Thanks,
Eilon
I'm not sure if this is related or not, but your call to
<%= Html.TextBox("newRunTime.Time", ViewData.Model.Time) %>
might actually pick the wrong overload (since Time is an integer, it will pick the object htmlAttributes overload, rather than string value.
Checking the rendered HTML will let you know if this is occurring. changing int to ViewData.Model.Time.ToString() will force the correct overload.
It sounds like your issue is something different, but I noticed that and have been burned in the past.
Seb, I'm not sure what you mean by an example. I don't know anything about Unity configuration. I'll explain the situation with Castle.Windsor and maybe that will help you with to configure Unity correctly.
By default, Castle.Windsor returns the same object each time you request a given type. This is the singleton lifestyle. There's a good explanation of the various lifestyle options in the Castle.Windsor documentation.
In ASP.NET MVC, each instance of a controller class is bound to the context of the web request that it was created to serve. So if your IoC container returns the same instance of your controller class each time, you'll always get a controller bound to the context of the first web request that used that controller class. In particular, the ModelState and other objects used by the DefaultModelBinder will be reused, so your bound model object and the validation messages in the ModelState will be stale.
Therefore you need your IoC to return a new instance each time MVC requests an instance of your controller class.
In Castle.Windsor, this is called the transient lifestyle. To configure it, you have two options:
XML configuration: you add lifestlye="transient" to each element in your configuration file that represents a controller.
In-code configuration: you can tell the container to use the transient lifestyle at the time you register the controller. This is what the MvcContrib helper that Ben mentioned does automatically for you - take a look at the method RegisterControllers in the MvcContrib source code.
I would imagine that Unity offers a similiar concept to the lifestyle in Castle.Windsor, so you'll need to configure Unity to use its equivalent of the transient lifestyle for your controllers.
MvcContrib appears to have some Unity support - maybe you could look there.
Hope this helps.
Having come across similar problems when attempting to use the Windsor IoC container in an ASP.NET MVC app I had to go through the same voyage of discovery to get it working. Here are some of the details that might help someone else.
Using this is the initial setup in the Global.asax:
if (_container == null)
{
_container = new WindsorContainer("config/castle.config");
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(Container));
}
And using a WindsorControllerFactory which when asked for a controller instance does:
return (IController)_container.Resolve(controllerType);
Whilst Windsor was correctly linking up all of the controllers, for some reason parameters were not being passed from the form to the relevant controller action. Instead they were all null, though it was calling the correct action.
The default is for the container to pass back singletons, obviously a bad thing for controllers and the cause of the problem:
http://www.castleproject.org/monorail/documentation/trunk/integration/windsor.html
However the documentation does point out that the lifestyle of the controllers can be changed to transient, though it doesn't actually tell you how to do that if you are using a configuration file. Turns out it's easy enough:
<component
id="home.controller"
type="DoYourStuff.Controllers.HomeController, DoYourStuff"
lifestyle="transient" />
And without any code changes it should now work as expected (i.e. unique controllers every time provided by the one instance of the container). You can then do all of your IoC configuration in the config file rather than the code like the good boy/girl that I know you are.