Aug152011

Visual Studio 2010 not signing?

Published by volkanuzun at 12:54 AM under C#

I created a class library project, and I had to sign the dll, so I created a signing key using Visual Studio 2010. I also created a password to protect my key.
After some work on the code, I figured out that, the project assembly name is not good so I renamed the assembly. I continued my work, and it was time to use this dll in an another project; I needed the public key token for the dll; so I used the sn tool to get the public key token:

sn -T <dll name>
I got an error , complaining that the public token for this dll is null. First I thought this is because I did not run the command console with admin privileges; but that was not it. I opened the class library project again, confirmed that sign dll option is checked.; unchecked the option, checked it again; it did not work.

The solution was:

  1. Uncheck the sign option and delete the key from the project
  2. Clean the solution
  3. Generate a new key, with the same password, and check the sign option again
  4. Compile the project

 

This worked; apparently if you change the assembly name, after you sign the dll, something gets broken, and Visual Studio can not sign the dll anymore.



[KickIt] [Dzone] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Tags:

E-mail | Permalink | Trackback | Post RSSRSS comment feed 0 Responses

Mar222011

Load Balancer sending 302 not 307! ViewState is missing?

Published by volkanuzun at 9:39 PM under Network and Software Issues | ASP.NET | Security

   Recently one of customers reported a bug with our product. They told us that our software does not work when there is a load balancer. First let me explain their environment to give a better understanding we had an issue.

At their environment there is a load balancer that is holding the SSL certificates, anything behind the load balancer is not SSL enabled. When a client connects to a server behind the load balancer using https, load balancer strips out the https section of the package, and send it to one of servers in http protocol (not https).  Furthermore the company network policy says that you can not talk to any servers without using https. So basically even if “Server A” behind the load balancer tries to talk to “Server B” behind the load balancer, it has to be https (and of course load balancer will strip out the certificate from the communication). The reason for this setup is so that all the certificates are installed into load balancer not individual servers.

Our software is making a post request to one of the pages on the same server, sending some data. The problem is the page that is receiving the post data does not receive the post data, and throws an exception. After checking the fiddler logs, we saw what the problem was. Let me try to explain it by telling you the workflow.

  1. 1. Client hits the server that hosts our product using https protocol; assume this is: https://contoso.com/default.aspx.

2. Load balancer.gets the request, strips the https section, and calls http://contoso.com/default.aspx.

3. Our page gathers some data, and posts the data to list.aspx pages on the same site, but as it is landing to default.aspx with http, it trying to post the data to http://contoso.com/list.aspx, and don’t forget that this is post request.

4. Load Balancer gets the request, and knowing about the https policy, it sends a http 302 (redirect) to https://contoso.com/list.aspx instead of http. Himm this is a redirect with get, but we posted data in the previous step, and what happened to that data? GONE.

5. list.aspx page tries to read post data, and some viewstate as well and fails because the expected data is not received.

Load balancer should never change a post request to a get request, and one of the solutions to this problem is, configuring the load balancer to send http 307 (redirect post with user agent), in stead of 302.

The other solution can be installing the same certificates to the server.behind the load balancer, and telling the load balancer to use https between servers and itself.



[KickIt] [Dzone] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Tags:

E-mail | Permalink | Trackback | Post RSSRSS comment feed 0 Responses

Feb192011

Check Permissions throws exception (SharePoint 2010)

Published by volkanuzun at 11:23 PM under SharePoint

I am working on a claims provider module for SharePoint 2010. I completed almost all the functionality, and now it was time to test the provider using the UI. It passed all the tests except one. When I try to check permissions for a secruity group, I was getting an exception, and SharePoint was displaying the default exception window. At first; I thought it was my code; and I debugged the code, and did not see any problem with the code. Then I decided to do the thing that I was supposed to do first; check SharePoint logs with ULSViewer. When I check the logs, the error message was:
System.InvalidOperationException: Operation is not valid due to the current state of the object. at Microsoft.SharePoint.SPUserToken.GetClaimsUserLoginName()
It was obvious that this could not be my code, as I don't call GetClaimsForUserLoginName, so I decided to google this error message; and bumm first hit was to MSDN. I installed this patch, and it fixed my problem. I wonder how did this bug not catch before SharePoint 2010 release? It is one of the very core functionality for a provider (check permission).


[KickIt] [Dzone] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Tags:

E-mail | Permalink | Trackback | Post RSSRSS comment feed 0 Responses

Jan032011

Infinite loop between STS and SharePoint

Published by volkanuzun at 4:47 PM under SharePoint

    If you setup SharePoint to use a STS for authentication, you may have an infinite loop problem like I did :) Here was my scenario:

I have a custom STS, and I setup a trust relation between this STS and SharePoint. When I try to login to a site, as expected, the browser is forwarded to STS login page. I typed in my username and password, then browser started redirection to SharePoint and then again back to STS. This was an infinite loop, and it was weird that Internet Explorer does not complain when there is an infinite loop.

Anyway, when I googled this situation, first link was: Setting the Login Token Expiration Correctly for SharePoint 2010 SAML Claims Users. I applied the suggestions which basically were changing the default timeouts. However this did not fix the problem.

I started thinking about the scenarios that could cause this problem. I know from the logs that STS login worked perfectly ok, and it created claims, and sent it to SharePoint. SharePoint was probably refusing the claims, and sending the user back to STS, STS was redirecting to SharePoint again (as there was a session cookie after then authentication) … The problem was when I was setting up the claims, I had a typo, and SharePoint was expecting another claim from STS, and hence causing the infinite loop.

I fixed the claim typo problem, and tried it again, nope again infinite loop. with the help of my one of my colleagues, we found the problem. When I click the site from IIS manager (click browse link next to the site), IIS is using localhost address, and this was causing the infinite loop. However when I type in the real address (not the localhost one), everything was working as expected :)



[KickIt] [Dzone] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Tags:

E-mail | Permalink | Trackback | Post RSSRSS comment feed 1 Responses

Oct142010

A potentially dangerous Request.Form value was detected from the client (wresult="

Published by volkanuzun at 3:58 PM under

I created my first sample WIF application after hearing so much about it. I used the ASP.NET MVC default project that comes with Visual Studio 2010 using .NET 4.0.  I did not do anything special just created the ASP.NET MVC project, right clicked on the project, clicked add the sts reference and ran the project. The browser was forwarded to the login page, I put some random password, and clicked login button. I got the error you see in the title: “A potentially dangerous Request.Form value was detected from the client (wresult="<trust:RequestSecuri...").”
The reason for this error is the claim coming back from the STS project is xml format, and that triggers and fails the ASP.NET validation. What you have to do is write a custom validation, and configure your application to use this custom validation. WIF SDK has a sample custom validation which under default installation is at: “C:\Program Files (x86)\Windows Identity Foundation SDK\v4.0\Samples\Quick Start\Web Application\WebControlBasedClaimsAwareWebApp\App_Code\SampleRequestValidator.cs”.

There is a class in this file that derives from: RequestValidator and overrides IsValidRequestString. In this function it checks if the request is coming from our STS service or not. If it is not coming from our service, basically it calls the base validator. Here is the code that does this:

public class WIFRequestValidator:RequestValidator
    {
        protected override bool IsValidRequestString(HttpContext context, 
string value, RequestValidationSource requestValidationSource,
string collectionKey, out int validationFailureIndex) { validationFailureIndex = 0; if (requestValidationSource == RequestValidationSource.Form && collectionKey.Equals(WSFederationConstants.Parameters.Result,
StringComparison.Ordinal)) { SignInResponseMessage message =WSFederationMessage.
CreateFromFormPost(context.Request) as SignInResponseMessage; if (message != null) return true; } return base.IsValidRequestString(context, value,
requestValidationSource, collectionKey,
out validationFailureIndex); } }

 

To use this validator in your application instead of the default ASP.NET validator, you have to modify web.config file. Open up the web.config file, and add/modify this line as follows:

<httpRuntime requestValidationType="WIF2.WIFRequestValidator" />

 

Now you run the code and you probably get your second error message:

ID1038: The AudienceRestrictionCondition was not valid because the specified Audience is not present in AudienceUris.

I don’t know if this is a bug in the WIF system or not, but to solve this issue, you need to modify the web.config for the web application one more time. Go to the line where you see:
“<wsFederation passiveRedirectEnabled..
and go to section realm=”… and add a / to the end of the url. Such as in my config file before I did the update it was:
realm=http://localhost/wif2
and I changed it to:
realm=http://localhost/wif2/

That is it :)



[KickIt] [Dzone] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Tags:

E-mail | Permalink | Trackback | Post RSSRSS comment feed 0 Responses

Oct102010

New Era

Published by volkanuzun at 2:28 AM under

I am changing my programming interests in the last few months. I am more interested in security, windows identity foundation, federated authorization and Sharepoint.  I am not new into security,  I presented OWASP Security Vulnerability, many times I was the one helping to fix the SQL injections or other security vulnerabilities found at work.
However I am new to Windows Identity Foundation and Sharepoint. I installed Sharepoint a virtual machine and started playing with it. Unfortunately Sharepoint is not very intuitive and user friendly. Most of the actions are not at the places you look for. As far as I can experience in the last 1 month, it is not developer friendly either :). All the resources you find are for beginners, and advanced blogs do not share the source code.

I will start sharing what I learn about Sharepoint and WIF in this blog from beginner to advanced level :)

Let the games begin…



[KickIt] [Dzone] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Tags:

E-mail | Permalink | Trackback | Post RSSRSS comment feed 0 Responses

Jul022010

Socal CodeCamp Reviews

Published by volkanuzun at 9:33 PM under

I attended the 2 day Socal CodeCamp in San Diego which is a great event that I think all the developers in the area should attend. I am a frequent CodeCamp attendee :) , and usually enjoy the sessions.

I did not see a huge crowd this time at the CodeCamp (purely personal observation, you should talk to CodeCamp management for real data which says one of the most crowded codecamp in San Diego). It is summer time, people may have more fun stuff to do such as surfing :). Actually I even heard someone would go surfing in between  sessions :).

If you look at the interest tag cloud for the sessions this time there are lot of Sql Server, Silverlight, 101 XXX, Step by Step XXX.  It seems that people are interested in Beginner Level sessions. Once again this is purely personal observation, and people may attend different sessions and choose other sessions :). 
Overall the quality of the sessions that I attended were good, I mean when it is free, why would you complain right? But I still will :)).

I think some hours of the codecamp should be purely dedicated to more advanced sessions. Such as on Saturday sessions at 9 – 12, all sessions are advanced, this will help to arrange schedule for visitors.

Another issue, is lot’s of repeating.  Microsoft is coming out with lot’s different tools, and other communities such as Mono community is coming with lot’s different tools, and we don’t get a change to listen any talks about most of these.  I know the real question is then why don’t take the steps and learn one of these and give a talk :) Well, for this fall I am planning about it.



[KickIt] [Dzone] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Tags:

E-mail | Permalink | Trackback | Post RSSRSS comment feed 0 Responses

Mar272010

HandleError attribute (MVC)

Published by volkanuzun at 2:42 PM under MVC

    In ASP.NET MVC you can decorate the action methods and the controllers with filter attributes to control their behavior.  These filters are injected into the pipeline, and depending on their type; they are executed before/after something happens. You can either use the filters that come with the framework, or write your own filters. Even though it is easy to test the functionality of the filters, it may not be easy to test if the controller/action is/are decorated with the filter (You can use reflection).  There are 4 different types of filters that come with the framework:

  • Authorization Filter: These type of filters have very high priority, and run before other types of filters or the action execution.
  • Action Filter: These type of filters have normal priority, and run before and after the action execution, by this way you can do some work before  an action is executed or after an action is executed. A good example could be logging the system activity, or calculating the time that takes to execute the action.
  • Result Filter: These type of filters have  normal priority, and run before and after the action result is executed, by this way, you can manipulate the action results.
  • Exception Filter: These filters are executed if an unhandled exception is thrown.

In this blog posting I will be explaining HandleError attribute which is a type of Exception Filter. You may want to use this filter to catch the exception for either logging the exception to a log file or display a nice error page so the user does not freak out.  If you create a default MVC project using Visual Studio, you will see that the HomeController class is decorated with HandleError filter.

[HandleError]
public class HomeController : Controller


This means whenever there is an exception that is not handled, render the Error view, so when there is an exception the framework will first look at the folder “Views/Home” and check if there is an Error.aspx page (assuming you are using the default WebForms Engine). If it can not find this page, it will check if there is a Error.ascx page, if there is none, then the same search will be applied to Shared folder. Finally if there is an Error.aspx/ascx page found it will be rendered, otherwise, in the production system, IIS will handle error, in the development system you may see the error below (depending on your web.config customErrors setting).

image

Or if you use the HandleError filter, and configure your system right, this may be the screen:

image

Of course you want to the second user friendly error page. Let’s first see what we should be doing to get the simple user friendly user page and then we will look into customizing this error page.

  1. Decorate the controller or the action method with HandleError
  2. Create an Error.aspx or Error.ascx page, and put this page either into the View folder of the controller or Shared folder.
  3. Open your web.config file and change the custom errors definition to customErrors mode=”On”


After this 3 simple steps, you have  an Error page that will be displayed whenever there is an unhandled exception.

HandleErrorAttribute is defined in the HandlErrorAttributed.cs (suprised?) file. It is a relatively simple and short code. If you check the source code, you will see that there are parameters you can customize.  Here are the list of the parameters that you can customize:

  • View: You can define a new View besides the Error to render for the error message. If you don’t specify a View name, default View name is Error
  • Master: You can define a master page for the View that will be rendered. If you don’t specify a master name, that it is empty by default, which means it will use the default master page.
  • ExceptionType: The exception type that you want to handle, by default it is the very generic System.Exception which means catch all the exceptions.

Note that there is another field you can customize however it is not a direct member of this class, but it comes with inheritance. 
Going back to our example, if we want to change error page name to let’s say “UnderMaintenance” , simple change your filter decoration to:

[HandleError(View="UnderMaintenance")]
public class HomeController : Controller


Or if you want to change the master page to Maintenance simply change your filter decoration to:

[HandleError(View="UnderMaintenance", Master="Maintenance")]
public class HomeController : Controller


Now let’s assume you want to redirect the user to different pages for different types of exceptions, then you have to use the ExceptionType property.

  • If the View you are trying to render is not found, then InvalidOperationException will be thrown.
  • If you are trying to connect to SqlServer, and there is an error, then System.Data.SqlClient.SqlException will be thrown

For other types of exception you can check MSDN, but let’s now concentrate on these 2 exceptions, and create 2 different error pages for 2 different types of Exceptions. Here is the right decoration for this goal:

[HandleError(View="Error", ExceptionType=typeof(InvalidOperationException))
[HandleError(View="DatabaseError",ExceptionType=
typeof(System.Data.SqlClient.SqlException)) public class HomeController: Controller


By this declaration we are telling the system that when there is an InvalidOperationException render the Error.aspx/ascx, when there is a SqlException  error, render DatabaseError.aspx/ascx view.

What happens when we add another HandleError that handles the SystemException which is basically all the exceptions, so if our declaration is like below, and assume SqlException is thrown:

[HandleError(ExceptionType=typeof(InvalidOperationException))]
[HandleError(ExceptionType=typeof(System.Data.SqlClient.SqlException))]
[HandleError(ExceptionType = typeof(SystemException))]
 public class HomeController : Controller


The framework will call  the all filters that can catch this type of exception, in this case, framework will call handlerror twice, one for the SqlException, and one for the SystemException.

You can write your own HandleError filter, and apply it to the controller or action. Inside this filter, you have to set the ExceptionHandled flag to true, so that framework won’t throw the yellow dead screen. If there are more than 1 filter that can catch the error message, all of them have to set the ExceptionHandled flag to true, or framework will throw the yellow dead screen.
The default HandleError attribute also creates a model for your view incase you want to get more information about the error, if you change your error page’s model to HandleErrorInfo, then you can get more information from the framework about the error. A simple example for the Error.aspx could be:

<%@ Page ..  Inherits="System.Web.Mvc.ViewPage<HandleErrorInfo>" %>
Sorry for the error, We are working hard on it to fix the problem.
<ul>
    <li>Action: <%=Model.ActionName %></li>
    <li>Controller: <%=Model.ControllerName %></li>
    <li><%=Model.Exception.ToString() %></li>
</ul>

 

Of course in the real work application, you don’t want to display this information to your user, but you can use this information to write a log to your log system.
Hopefully this article help you to understand HandleError attribute.

May the force be with you.



[KickIt] [Dzone] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Tags: , , ,

E-mail | Permalink | Trackback | Post RSSRSS comment feed 0 Responses

Mar262010

T4MVC

Published by volkanuzun at 11:39 PM under T4MVC

    I presented ASP.NET MVC last month at San Diego .Net User group, I think overall it was a successful presentation. I got some good comments after the presentation, and yesterday, one member of the user group asked me my demo code for the T4MVC. Unfortunately I write my demos on the fly during my presentation ( I am not afraid to write code :) ), and usually 2-3 weeks after my presentation I wipe out the virtual pc that I use for the presentation. I don’t like to turn down people, I offered him to write a simple code that utilizes T4MVC, and then writing a blog that explains T4MVC came to my mind :)

While I am writing code, I am trying to avoid literal strings/magic numbers as much as possible and try to use strongly typed helpers/variables/etc instead. Obvious reasons are to have compile time support, intellisense,  easier maintainable code. Sometimes it is not that easy to replace the literal strings, such as if you have a link to a stylesheet, or an image source in the img tag, the strings are not easily replaced. Won’t you like the idea that the compiler will throw a compile time error when the css file is not found, or the image is not found?
Ex:

<link href="../../Content/Site.css" rel="stylesheet" type="text/css" />


The above 1 line of html is taken from the sample mvc application you get, when you go File=>New App=>MVC App..  How are we going to replace the source of the css link with a strongly typed helper? You can do this in a few different ways, but the real easy way is to use an open source project called T4MVC.  You can find more information about this project at Codeplex 
Basically it is a T4 template that helps you to remove the magic strings from your MVC projects, and it runs on Visual Studio 2008 as well as Visual Studio 2010. As a quick example the html line above that adds the css could be converted into:

<link href="<%=Links.Content.Site_css %>" rel="Stylesheet" type="text/css" />


As you can see, we remove the magic string of “../../Content/Site.css” and put a strongly typed helper. Now  let’s download the files from the codeplex, and work on the project that Visual Studio creates when you create a new MVC application. The next thing is drag the the files “T4MVC.settings.t4” and “T4MVC.tt” to the root of your project into the solution explorer. Visual Studio will pop up a warning:
image

As these two files are script files that use using T4 template, the scripts will have full access to your project, and Visual Studio is friendly! warning. Just click OK and skip this window.  Even before you compile, if you check the solution explorer, there are more files generated by the T4 template.

image

T4MVC examined your project, created a list of all the magic strings, and  prepared strongly typed helpers. One of the generated files is T4MVC.cs and it has 2 classes for your use in your project. Scripts and Content classes (it is not a coincidence that you have these folders in the project), both are static classes under the namespace of Links.  These 2 classes are full with const strings. These const strings are used to replace your magic strings in your project, and if you add more magic strings in the code, just compile the project, and T4MVC will create the new const strings too.
Now if you check the html code above one more time, you will see that we use that Links namespace, and Content class. In this Content class, T4MVC converted the magic string to a const string named Site_css. 

Let’s assume we want to add the Jquery-1.3.2.js file to our site.master page, we could either use the old magic string way:

<script src="../../Scripts/jquery-1.3.2.js" 
        type="text/javascript" language="javascript" />    


or, you can use T4MVC to help us and write:

<script src="<%=Links.Scripts.jquery_1_3_2_js %>" 
          type="text/javascript" language="javascript" />


This time we used Links namespace and Scripts class, as you can notice the folder names become the class names.
To display another helper, I added a new image to this project with the name of “hour_glass.jpg”.  To display this image I can either use the magic strings such as:

<img src="../../Content/hour_glass.jpg" alt=""/>


or I can use T4MVC to and write this:

<img src="<%=Links.Content.hour_glass_jpg %>" alt="" />


Up to now we remove the magic strings for the image and scripts, and styles, let’s see what we can do with links. In the default project, we have to links in the master page:

<li><%= Html.ActionLink("Home", "Index", "Home")%></li>
<li><%= Html.ActionLink("About", "About", "Home")%></li>


Let’s rewrite these with T4MVC helpers:

<li><%=Html.ActionLink("Home",MVC.Home.Index()) %></li>
<li><%=Html.ActionLink("About",MVC.Home.About()) %></li>


So what happened here? T4MVC created a static class called Home, (it also created the static classes for Shared, and Account), and created the function Index() which basically calls the Index action  of HomeController. If the Index action has a parameter such as an integer then T4MVC will generated the code accordingly; an action that has a parameter of int:

public virtual ActionResult Index(int? id)


could be called like:

<li><%=Html.ActionLink("Home",MVC.Home.Index(5)) %></li>


So far, if you changed the signature of Index(), or delete the image , or change the name of the style you will get a compile error as they are all strongly typed helpers. Also Visual Studio helps you with intellisense to fill in those magic strings.
What if we want to remove the magic strings in the controllers too? Such as in the default MVC project, if you open the admin controller Logoff action is:

public virtual ActionResult LogOff()
{
    FormsAuth.SignOut();
    return RedirectToAction("Index", "Home");
}

This function has a magic string of “Index” and “Home”, we can use T4MVC to change these into strongly typed helpers too such as:

public virtual ActionResult LogOff()
{
   FormsAuth.SignOut();
   return RedirectToAction(MVC.Home.Index());
}


How about the routes in the global.asax.cs file? An example route:

routes.MapRoute(
   "Default",                                             
   "{controller}/{action}/{id}",                          
    new { controller = "Home", action = "Index", id = "" } 
 );


and this is how it is replaced using T4MVC:

routes.MapRoute("t4mvc",
  "{controller}/{action}/{id}",
   MVC.Home.Index()
 );

And the form we have in the Logon.aspx page of the AccountController:

<% using (Html.BeginForm()) { %>


could be converted into:

<% using (Html.BeginForm(MVC.Account.LogOn())) { %>


T4MVC works in routes, in views, in controllers, almost anywhere :), it has some problems too such as if you create a new folder, and add content to that folder, T4MVC won’t recognize this new folder, however it has good community support and these small items may be fixed, it also has some other support for MVC 2.0 and you can check these from its codeplex website.



[KickIt] [Dzone] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Tags: ,

E-mail | Permalink | Trackback | Post RSSRSS comment feed 4 Responses

Mar192010

TempData in MVC 1.0

Published by volkanuzun at 11:40 PM under MVC

    TempData is an interesting structure in MVC 1.0, and could be a little problematic if you don’t know the internals of it while using, so in MVC 2.0 TempData structure is changed. Today I want to analyze MVC 1.0’s TempData structure.

TempData is used to store information that will be consumed only once. A good example could be some information/error messages that will be passed to the view, and if the user refreshes the page, the message will be gone. For example:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Save(Order order)
{
    if(order.Validate()==false)
    {
        TempData["Msg"]="There are problems with order, please fix'em";
        return RedirectToAction("ValidationError");
    }
    //... some save to database action 
   TempData["Msg"]="Your order will be shipped ASAP";
  return RedirectToAction("OrderComplete");
}

As you can see in the code above, we are passing a message to one of the actions informing about the status of the order. If the user refreshes the page, TempData[“Msg”] will be cleared and the message will be gone. How does MVC 1.0 accomplish this? Basically, it stores the the value in the session, and after the roundtrip it deletes the value, but more technically:
If you open the MVC source code, and go to the Controller.cs file line 100, you will see that the controller has a member called TempDataProvider which is by default a SessionStateTempDataProvider. This provider implements an interface that has the below signature:

public interface ITempDataProvider {
  Dictionary<string, object> LoadTempData(ControllerContext controllerContext);
  void SaveTempData(ControllerContext controllerContext, 
IDictionary<string, object> values); }

So basically its job is to load or save a dictionary, and the SessionStateTempDataProvider is using the Session to load or save the dictionary. This dictionary is storing your temp values. 
Let’s check what SessionStateTempDataProvider LoadTempData does. The first thing the provider does is to get the dictionary from the controllercontext’s session. If the session does not return a value for the dictionary (in case you haven’t used the TempData in your code , then the session value is empty), then a new Dictionary<string,object> is instantiated and returned back to the caller.
If the session value has a value for the dictionary, then it is taken from the session, the session value is cleared, and dictionary is returned. After this point, there is no value for the dictionary in the session, so it is caller’s job to save the dictionary back to the session.
Here is the code from the mvc source code:

public virtual IDictionary<string, object> LoadTempData(ControllerContext 
controllerContext)
{ HttpContextBase httpContext = controllerContext.HttpContext; if (httpContext.Session == null) { throw new InvalidOperationException
(MvcResources.SessionStateTempDataProvider_SessionStateDisabled); } Dictionary<string, object> tempDataDictionary =
httpContext.Session[TempDataSessionStateKey] as Dictionary<string, object>; if (tempDataDictionary != null) { // If we got it from Session, remove it so that no other request gets it httpContext.Session.Remove(TempDataSessionStateKey); return tempDataDictionary; } else{ return new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); } }


SaveTempData is an easy operation, just take the passed the Dictionary and save it to the controllercontext’s session.  So far what we have seen is just a provider that stores a dictionary to the session, and reads a dictionary from the session. How does the controller use this provider to store and load the temp values? If you open the ControllerBase.cs file and go to line 21, you will see that the ControllerBase has a public property TempData of TempDataDictionary type. One of the problem is happening in this area. This dictionary has a Load and Save public functions, that uses SessionStateTempDataProvider (by default), to save and load the values. In order to do that, it uses 2 HashSets, one for the initial keys (the values that come back with the post back), the other HashSet is either for the keys that are newly added to the Dictionary or modified keys from the initial keys. By this way, the dictionary keeps track of who is added, who is supposed to be removed, who is updated.

The controller executes ExecuteCore() to invoke the action. The first line in this function is TempData.Load. This is where the controller asks the TempData dictionary to load the dictionary, and TempData dictionary uses SessionStateTempDataProvider to load the dictionary from the session. The last line of the ExecuteCore is TempData.Save which simply takes the dictionary back from the controller, uses SessionStateTempDataProvider and saves it to the session. Do not forget that the unmodified values are removed from the dictionary when the Save method is called.

What are the problems with this structure?
First of all TempData by default stores the dictionary in a session, and once it is read, it cleans the session. What if the user opens a new tab right before your TempData value is read by page? Session is shared between the tabs of the same browser, so TempData may lose the data in the session. The same problem may occur when there is an ajax call to the controller, or there is a redirecttoaction. Because of these problems MVC 2.0 has fixed some issues with TempData and we will look into the source for MVC 2.0 in a later posting.



[KickIt] [Dzone] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Tags:

E-mail | Permalink | Trackback | Post RSSRSS comment feed 0 Responses