ASP.NET MVC CookieTempDataProvider.DeserializeTempData returns null - asp.net-mvc

I've been trying to use CookieTempDataProvider to pass a basic message between a post (entity update) and a get (entity list) using the RedirectToAction method. When using the default TempData implementation this works fine, however when I use the cookie-based version from the MVC Futures project, the TempData dictionary is empty after the redirect. This is because the TempDataDictionary is returned as null from the DeserializeTempData method. I know exactly what line of code the problem occurs on, and I know how to fix it, but I can't believe that I'm the only one to have this problem.
Maybe I'm using the wrong version of the MVC Futures project, but I've just downloaded the ASP.NET MVC v1.0 source and the problem definitely exists there. Does anyone else use CookieTempDataProvider, and does it work for you?
The problem with the CookieTempDataProvider class, as I see it, is on line 62, where it is casting the deserialized object as TempDataDictionary instead of as IDictionary<string, object>. When I make this change, everything works perfectly.
Anyone else see this problem, or is it just me?

Same here. Didn't work after using assembly as is from MVC Futures. Changing line 62 as you suggested fixed the problem. Thanks for posting.

Related

Include in enity framework 4

I've been using enity framework that came with 3.5sp. And now I've redone things for enityframework 4 and asp.net mvc 2. I've come across something (which worked in my previous version and asp.net mvc 1.0).
I have this:
public IQueryable<Booking> GetBookings()
{
return from b in _entities.Bookings.Include("BookingObject")
select b;
}
And in my controller I have:
return View("Index", new BookingsViewModel
{
Bookings = _br.GetBookings().ByDay(DateTime.Today)
});
And it doesnt seem to include the "BookingObject"-entity, so I can type like <%= Model.Bookings.BookingObject.BookingObjectName %> in my view.
What might be missing here? Do I need to turn something on in the diagram for it to include entities or?
/M
No, it should work exactly as before. I'm assuming you have a navigation property BookingObject on your Booking item - but then the .Include() would error out if you didn't. I don't think there's anything else you need to set up, or at least not that isn't done by default. I'd verify the definition of the navigation property in the .edmx editor at least.
You're definitely using the final RTM EF4 code? We hit a bug in the final RC building incorrect SQL and returning no results for one specific include sequence, but it was a lot more complex than that.
Failing that I would use SQL Server Profiler to trace out the SQL it's using and try and debug that.

Is it possible to add a value in MVC2 RC DataTokens collection?

I'm using ASP.NET MVC2 RC and I have built security on top of the Areas/Controller/Action specification, using basically a table that tells the infrastructure which role has permission to execute which controller action.
The code I used to get the "area" was this
RouteData.Values["area"]
And then I checked that in the Database. My problem is that when I migrated from MVC 1 RTM to MVC2 RC, the area goes in the DataTokens collection, and if the controller that is being called is in the root area, the following code returns null
RouteData.DataTokens["area"]
Do you know if there's any way to tell MVC that if "area" is not in the DataTokens collection, it should have string.Empty?
I'm trying to avoid modifying my code to check that for null.
Thanks!
As a work around, you can manually add the value from RouteData.Values to RouteData.DataTokens. But ideally you need to address the root cause.
Here's the work around for the issue:
if (controllerContext.RouteData.Values.ContainsKey("area"))
{
ControllerContext.RouteData.DataTokens.Add("area", ControllerContext.RouteData.Values["area"]);
}
Why not simply check if RouteData.DataTokens["area"] is null (or empty) and assume the default area when it is?
Edit
Apologies, I didn't read the the last line of your question before answering. What's the issue with modifying the code?

ASP.NET MVC Response Filter + OutputCache Attribute

I'm not sure if this is an ASP.NET MVC specific thing or ASP.NET in general but here's what's happening. I have an action filter that removes whitespace by the use of a response filter:
public class StripWhitespaceAttribute : ActionFilterAttribute
{
public StripWhitespaceAttribute ()
{
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
base.OnResultExecuted(filterContext);
filterContext.HttpContext.Response.Filter = new WhitespaceFilter(filterContext.HttpContext.Response.Filter);
}
}
When used in conjunction with the OutputCache attribute, my calls to Response.WriteSubstitution for "donut hole caching" do not work. The first and second time the page loads the callback passed to WriteSubstitution get called, after that they are not called anymore until the output cache expires. I've noticed this with not just this particular filter but any filter used on Response.Filter... am I missing something?
I also forgot to mention I've tried this without the use of an MVC action filter attribute by attaching to the PostReleaseRequestState event in the global.asax and setting the Response.Filter value there... but still no luck.
This KB article may offer some insight into the root cause of this issue. While the filter 'breaks' caching in IIS6 it throws an error in IIS 7. This seems to be a design / test-time improvement at best.
UPDATE
Here's an official "answer" from MS Dev Support on this issue.
Question:
What is the alternative to response filtering in ASP.NET for modifying HTML rendered by another process when:
1. The other process cannot be modified
2. Post-cache substitution must be supported
Answer:
"Yes, you question is clear as blue sky and this is officially claimed to be not support. As Post-cache substitution would combine certain substitution chunks to the response bytes while response filtering expects to filter the raw bytes of the response(not modified). So the previously combined substitution chunks cannot be preserved anymore.
There is not an alternative from Microsoft so far."
AFAIK, the problem is that the action filters doesn't get executed if the request goes to the output cache. The AuthorizeAttribute works around this problem by calling some obscure Output Cache API. However, I don't think that is the best solution for what you're are trying to do.
You should be working with output cache, not around it. What you should be doing instead is making sure that the spaces are removed from the response before it gets stored in the output cache.
Update
It seems that attaching a filter, no matter what filter, disables the WriteSubstitution functionality as you suspect. I've tried following the trail in the HttpResponse class using reflector but I can't find any proof that confirms this suspicion. I think the answer lies within the HttpWriter class.
Another Update
It so happens that I'm currently reading the excellent book "Pro ASP.NET MVC Framework" by Steve Sanderson (buy it if you don't already have it). In chapter 10 he links to a post on his blog where he talks about partial output caching and the poor integration between the MVC framework and the output cache. I haven't tried the custom outputcache attribute in the post yet... I will try it out and let you know if it does anything to solve the problem.

Issues During ASP.NET MVC Upgrade from Preview 5 to Beta?

What issues or refactoring did you have to do when you upgraded from ASP.NET MVC Preview 5 to the newly released Beta version?
Issue number one: Yellow screen of death.
CS0234: The type or namespace name 'Mvc' does not exist in the namespace 'System.Web' (are you missing an assembly reference?)
Solution: I removed all references in my project and re-added them, pointing to the assemblies in program files\asp.net\asp.net mvc beta\assemblies, but that didn't solve the problem.
I had a system.web.mvc dll in the gac (no idea how). Tried to delete it. Unable to; assembly is required by one or more applications. Had to find the assembly as described here and delete the registry entry. I was then able to remove the gac's version of system.web.mvc.
This STILL didn't fix the problem. I had to RE-ADD the references AGAIN. Now its working.
Just to be clear!!! The beta assemblies were dropped under Program Files, while an older version of System.Web.Mvc was in the GAC.
I'm about to do this myself. Here's the list of changes from the readme:
Changes Made Between CodePlex Preview 5 and Beta
Changed the default validation messages to be more end-user friendly.
Renamed CompositeViewEngine to AutoViewEngine.
Added a Url property to Controller of type UrlHelper. This makes it convenient to generate routing-based URLs from within a controller.
Added the ActionNameSelectorAttribute abstract base class, which serves as the base type for ActionNameAttribute. By inheriting from this base attribute class, you can create custom attributes that participate in action selection by name.
Added a new ReleaseView method to IViewEngine that allows custom view engines to be notified when a view is done rendering. This is useful for cleanup or for view-pooling scenarios.
Renamed the ControllerBuilder method DisposeController to ReleaseController to fit with the pattern that is established for view engines.
Removed most of the methods on the HtmlHelper class, converting them to extension methods of the HtmlHelper class instead. These methods exist in a new namespace (System.Web.Mvc.Html). If you are migrating from Preview 5, you must add the following element to the namespaces section of the Web.config file:
<add namespace="System.Web.Mvc.Html"/>
This makes it possible for you to completely replace our helper methods with your own.
Changed the default model binder (DefaultModelBinder) to handle complex types. The IModelBinder interface has also been changed to accept a single parameter of type ModelBindingContext.
Added a new HttpVerbs enumeration that contains the most commonly used HTTP verbs (GET, POST, PUT, DELETE, HEAD). Also added a constructor overload to AcceptVerbsAttribute that accepts the enumeration. The enumerated values can be combined. Because it is possible to respond to HTTP verbs that are not included in the enumeration, the AcceptVerbsAttribute retains the constructor that accepts an array of strings as a parameter. For example, the following snippet shows an action method that can respond to both POST and PUT requests.
[AcceptVerbs(HttpVerbs.Post | HttpVerbs.Put)]
public ActionResult Update() {...
}
Modified the RadioButton helper method to ensure that every overload accepts a value. Because radio buttons are used to specify a choice from a set of possible values, specifying a value for a radio button is necessary.
Made modifications and fixes to the default project template. This includes moving script files to a new Scripts folder. The default template uses the ModelState class to report validation errors.
Changed action-method selection. If two action methods match a request, but only one of those has an attribute that derives from ActionMethodSelectorAttribute that matches the request, that action is invoked. In earlier releases, this scenario resulted in an exception.
For example, the following two action methods are in the same controller:
public ActionResult Edit() {
//...
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(FormCollection form) {
//...
}
In Preview 5, a POST request for the Edit action would cause an exception, because two methods match the request. In the Beta, precedence is given to the method that matches the current request via the AcceptVerb attribute. In this example, the first method will handle any non-POST requests for the Edit action.
Added an overload for the ViewDataDictionary.Eval method that accepts a format string.
Removed the ViewName property from the ViewContext class.
Added an IValueProvider interface for value providers, along with a default implementation, DefaultValueProvider. Value providers supply values that are used by the model binders when binding to a model object. The UpdateModel method of the Controller class has been updated to allow you to specify a custom value provider.
I experienced the same problem as Will and had to do similar things as him, including copying the dlls to the bin folder.
Now things are working in the internal vs.net server but are causing IIS7 to crash.
Ok, it turns out one of the major problems is that I missed the step to update the compilation assemblies in the web.config:
<add assembly="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
All i had to do was update the assemblies from
%ProgramFiles%\Microsoft ASP.NET\ASP.NET MVC Beta
Also get the most recent Microsoft.Web.MVC from codeplex
to update my futures assembly too.
add in 2 lines to the web.config
This one to the <assemblies> Section:
<add assembly="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
This one to the <namespaces> section:
<add namespace="System.Web.Mvc.Html"/>
Then i had to update all the <%using (Html.Form()) to <%using (Html.BeginForm())
On one code file i had to add the System.Web.Mvc.Html; namespace
My stuff is based on Rob Conery's MVC Storefront, so anyone using that should be able to follow the above.
Hope it helps someone out there.
Disregard this... I'm a loser - it's Microsoft ASP.net in program files... not just ASP.net
Maybe this should be a second question, but I think keeping it all in one place might help.
When running the Beta installer nothing ends up changing on my PC. I don't see the folder in the Program Files folder... no assemblies are added to the GAC... even the installer gets to the last step and then hangs for around 10 minutes or so.
I've uninstalled and reinstalled a couple times now without any luck.
Anyone having a similar problem?
The problem with AutoFac has now been resolved in Revision 454 of the AutoFac code base
http://code.google.com/p/autofac/issues/detail?id=86&can=1
Im trying to find out how the new ModelBinder works, as far as I can see it's very different, but i haven't managed to find out how it works yet..
My old looked like:
public class GuestbookEntryBinder : IModelBinder
{
#region IModelBinder Members
public object GetValue(ControllerContext controllerContext, string modelName, Type modelType, ModelStateDictionary modelState)
{
if (modelType == typeof(GuestbookEntry))
{
return new GuestbookEntry
{
Name = controllerContext.HttpContext.Request.Form["name"] ?? "",
Website = controllerContext.HttpContext.Request.Form["website"] ?? "",
Message = controllerContext.HttpContext.Request.Form["message"] ?? "",
};
}
return null;
}
#endregion
}
The new one looks like:
#region IModelBinder Members
public ModelBinderResult BindModel(ModelBindingContext bindingContext)
{
throw new NotImplementedException();
}
#endregion
Any hints?
I use Autofac as my DI container. A null container exception gets thrown when trying to dispose of the container objects.
Yup, also use Autofac as DI container.
Get same issue as this guy
http://groups.google.com/group/autofac/browse_thread/thread/68aaf55581392d08
No idea if a fix is possible but cant continue until this is fixed ......
After struggling with this for most of the day, I figured I'd post my solution here. Maybe this is normal Visual Studio behavior but I never noticed it before...
On my existing project, I actually had to manually move the Beta files to the Bin folder. For whatever reason, just browsing to it with Add Reference wasn't working...
Html.TextBox - value now is object, not string.
So, hidden errors possible (not at compile time and even not at runtime), for example I've used this overloaded method earlier Html.TextBox(string name, object htmlAttributes). Now my attrs go into textbox value.
About the Autofac issue. There is a thread on the autofac discussion group about the need to update the controller factory to be compatible with the Beta release of the MVC framework
http://groups.google.com/group/autofac/browse_thread/thread/68aaf55581392d08
I hope they post a new version very very soon :-)
When I upgraded from Preview 5 to Beta I had difficulty locating the generic overloads of ActionLink. It appears that those are not included in the main release of ASP.NET MVC but are being shipping as "futures".
I found the necessary assembly (Microsoft.Web.Mvc) # http://www.codeplex.com/Release/ProjectReleases.aspx?ProjectName=aspnet&ReleaseId=18459
There is a breaking change in the ViewContext constructor. It has changed from:
ViewContext(ControllerContext context, string viewName, ViewDataDictionary viewData, TempDataDictionary tempData)
to:
ViewContext(ControllerContext context, IView view, ViewDataDictionary viewData, TempDataDictionary tempData)
This broke my code because I am using MvcContrib.Services.IEmailTemplateService, which takes a ViewContext in its RenderMessage method. To get an IView from the template name, I am doing the following:
var view = ViewEngines.DefaultEngine.FindView(controllerContext, viewName, null);
Not sure if this is the best practice, but it seems to work.
This is now broken:
<%=Html.TextBox("Name", new Hash(#class => "required"))%>
In Preview 5 the above would bind the value of ViewData.Model.Name to the textbox. This still works:
<%=Html.TextBox("Name")%>
But if you want to specify html attributes, you must also specify the value as follows:
<%=Html.TextBox("Name", ViewData.Model.Name, new Hash(#class => "required"))%>
Actually this is not really safe. If there is any chance ViewData.Model might be null you need to do something like this:
<%=Html.TextBox("Name", ViewData.Model == null ? null : ViewData.Model.Name, new Hash(#class => "required"))%>
This change seems counter to the Beta release notes:
"...in order to reduce overload
ambiguity...the value parameter was changed
from object to string for several
helper methods."
The value parameter for TextBox used to be string, and it was changed to object. So to avoid ambiguities they had to remove the one overload that I use the most. :(
IMHO, every HTML helper method should have overloads that allow binding in all cases without specifying the value. Otherwise we will end up with inconsistent view code that will confuse future devs.
If you are using Html.Form from the futures assembly (Microsoft.Web.Mvc) you might get a name collision on the FormMethod enum. For example:
Html.Form<FooController>(c => c.Bar(), FormMethod.Post, new Hash(#class => "foobar"))
This will complain that FormMethod is an ambiguous reference between Microsoft.Web.Mvc and System.Web.Mvc. This is quite sad because IMHO BeginForm does not provide a viable option due to its lack of an override that uses a lambda expression. Your only option is to use magic strings, which resist refactoring.
The best solution, it seems, is to put the following into every view that uses FormMethod:
<%# Import Namespace="FormMethod=Microsoft.Web.Mvc.FormMethod"%>
Ugh. Hopefully this is temporary. I expect that the futures assembly can be changed to use the enum from System.Web.Mvc. Or much better yet, hopefully they overload BeginForm to use expressions.
It seems that Html.Image is broken. As of preview 5 it was moved to the futures assembly. I cannot imagine why. Anyway, the error is:
Method not found: 'Void System.Web.Mvc.UrlHelper..ctor(System.Web.Mvc.ViewContext)'
The best solution I can see is to replace this:
<%=Html.Image("~/Content/Images/logo.jpg") %>
with this:
<img src="<%=Html.ResolveUrl("~/Content/Images/logo_350.jpg")%>" />
What Will said above, except that in addition to deleting the assemblies from the GAC and re-adding the references I also had to run the Beta installer again (putting the right assemblies in the GAC this time, though I'm just using a file reference).
I suspect if I'd deleted the Preview 5 assemblies from the GAC (and I've no idea how they got in there either) before I ran the installer, everything might have been OK. Worth trying.
In the unlikely event that anyone else out there is as daft as me and working on Vista, you may not need to do the registry hacking above in order to delete the old assemblies - just run gacutil from an admin command prompt. Doh!
I found that updating the web.config namespaces element with the namespaces from a blank project fixed my problems. I also had to update my ModelBinders due to the interface change.

Asp.Net MVC Beta: Previous RouteData overrides current RouteData?

I have something similar to the following method:
public ActionResult Details(int id)
{
var viewData = new DetailsViewData
{
Booth = BoothRepository.Find(id),
Category = ItemType.HotBuy
};
return View(viewData);
}
and the following Route:
routes.MapRoute("shows","shows/{controller}/{action}/{id}", new {id = 0});
Everything worked fine before the Beta, when I had Preview 3. Now the method will fill the id correctly the first time I execute the action. However the second time the controller's ModelState contains the last-use id value. This causes the ActionInvoker to use it in the method's parameter instead of the Route value.
So if I call the action twice on two different entities the results are such:
www.mysite.com/shows/Booth/Details/1 => Details(1)
www.mysite.com/shows/Booth/Details/2 => Details(1) //from ModelState["id"]
From my quick scan with Reflector it seems it first binds parameters to the ModelState then to Routes. However, I never even posted anything from the model. As far as I can tell the ModelState should not contain anything.
Is this a bug in the Beta, possibly a bug somewhere in my code, or is there some design feature that I am ignorant of? Any insight into the nature of ModelState and why this happens is appreciated.
EDIT:
I discovered that this issue is actually a symptom of what appears to be a bug with the DefaultValueProvider if you instantiate a Controller from an IoC container that exists for the lifetime of the Asp.Net application.What happens is that the DefaultValueProvider uses the first ControllerContext given to the Controller and never updates it until the controller is recreated. This causes old RouteData to be used for method parameters instead of the current RouteData.
It's hard for me to tell what you expect to happen and what is happening from your post. Is it possible there's an error in your BoothRepository.Find method such that it returns the same thing every time?
ModelBinder should not be affecting this method because the parameter to the action method is a simple type, int.
Were both of these requests GET requests? If you still are having problems, can you try and create the simplest repro possible and email it to philha - microsoft dot com?
EDIT: The problem ended up being that the developer was attempting to re-use the valueprovider across requests (by having Castle Windsor manage the lifecycle of Controllers). Right now, there's no support for re-using controller instances across requests like you would with IHttpHandler which has a IsReusable property. So in general, reusing controllers across requests requires doing a lot more work on your end. :)
The problem is the LifeStyle, I completetly overlooked the fact it was being defined, which means by default the controllers will use the Singleton lifestyle. Setting the LifeStyle to Transient for all controllers will sort this problem.
if you use spring.net modify
Controller's singleton to "false"
This is a common issue when using Singleton behavior with a IoC container such as Spring.NET or Windsor. Controllers should not have singleton behavior because the ControllerContext is per request, much like HttpContext.

Resources