11

I am building an MVC application. It behaves so weird. If I run it on my development server (visual studio debugging) it runs fine even when I restart my application several times by changing the web.config, but when I hosted it, it behaves so weird.

For the first load, everything is normal. I can load all pages, post via ajax, etc just normal, but after I restart the server using HttpRuntime.UnloadAppDomain(); then everytime I post via ajax, I always get

internal server error 500

I do not know what is happening with the application, but I have suspicion that something is going wrong with the client (user) cache / cookies.

I use [ValidateJsonAntiForgeryToken] attribute to the controller functions that receive the post.

[HttpPost]
[ValidateJsonAntiForgeryToken]
public JsonResult LoadPage(int id, string returnUrl, PageFormViewModel pageForm, string jsonFormModel)

And this is the code that handles the json validation token

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class ValidateJsonAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException("filterContext");
        }

        var httpContext = filterContext.HttpContext;
        var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
        AntiForgery.Validate(cookie != null ? cookie.Value : null, httpContext.Request.Headers["__RequestVerificationToken"]);
    }
}

This is the example how I post it:

var getURL = $('#GetURL').val();
var returnUrl = $('#ReturnUrl').val();
var pageId = $('#PageId').val();
var token = $('input[name="__RequestVerificationToken"]').val();
var headers = {};
headers['__RequestVerificationToken'] = token;

var thePageForm = pageForm;
var theFormModel = formModel;

$.ajax({
    type: 'POST',
    url: getURL,
    contentType: "application/json; charset=utf-8",
    dataType: 'json',
    async: false,
    headers: headers,
    data: JSON.stringify({ id: pageId, returnUrl: returnUrl, pageForm: thePageForm, jsonFormModel: theFormModel }),
    success: function (model) { //Load the page }
    error: function()
});

I have @Html.AntiForgeryToken() in my view. Actually what is wrong with my application? If the problem is that the user cookie is still being accepted by the system but it is not valid, then how to make the user cookie reset after the application being restarted?

---------------------------

Update

It seems that the code is actually able to pass through the controller action, so there is no problem with the validation token, but when the code reached the line that tried to retrieve data from database, this happens

Message: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)

This is my connection string:

Conn string:Data Source=ip address;Initial Catalog=the database name;Integrated Security=False;User ID=user;Password=the password;MultipleActiveResultSets=True

This is the code that produces error:

PageViewModel model = new PageViewModel();
model.Page = dbPages.Pages.Where(m => m.Id == id).First();

If I run it using Incognito mode, it runs fine. So what is exactly going on with my application?

-------------------

Update 2

After a further debugging, I am sure now that the problem lies in the cookies.

These are the cookies:

  1. .ASPXAUTH
  2. ASP.NET_SessionId

I use "InProc" as my session state, which should be reset after application recycle / restart, which is my aim, but I do not know why after application restart, the cookies are still there.

So what I want is to invalidate the session for all user if the server is restarted.

The solution are either:

  1. Get all the sessions from all users and invalidate it
  2. Logout all logon users at Application_End()

Both solutions are impossible from my research. Please help

Alvin Stefanus
  • 1,873
  • 2
  • 22
  • 60
  • Internal server error 500, usually means that there was an unhanded exception in your C# code. Can you put a break point in your LoadPage controller action? – unicorn2 Dec 20 '16 at 08:47
  • I cannot do that because it is a release application, if I do that in my development server, there is nothing wrong, there is no error. I think the ajax post does not get past into my controller action, because I i put break point in my ajax code, it does not go pass into success or error. So i suggest there is something wrong with the token validation. ***The problem goes away if I running it in Incognito mode.*** So i think there is problem with cookies or cache. – Alvin Stefanus Dec 20 '16 at 08:58
  • Can you see the value of the token when you are posting? It seems to be coming from the html: input[name="__RequestVerificationToken"]. Are you doing the post only at document ready? – unicorn2 Dec 20 '16 at 09:05
  • Yes i can see the value, and it is inside document.ready, which is why it works fine before the server restarted. ***Also it works fine again after about 20 minutes after server restart***. So i think there is cookie / cache problem. – Alvin Stefanus Dec 20 '16 at 09:23
  • When you get a Internal server error 500 you usally have a entry in the windows eventlog with a more detailed error message, have you looked? – Daniel Stackenland Dec 20 '16 at 09:30
  • 1
    @Alvin Stefanus are you expecting the session to still be there after restarting IIS? Have a look at this answer: http://stackoverflow.com/questions/3515947/losing-session-state – unicorn2 Dec 20 '16 at 09:32
  • What is the mode of your sessionState, in your Web.config? https://msdn.microsoft.com/en-us/library/ms178586.aspx – unicorn2 Dec 20 '16 at 09:53
  • I am able to put a debugger code at my controller action, it seems that the code is able to get pass it, but then when the code tried to access the database this happens `Message: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)` – Alvin Stefanus Dec 21 '16 at 05:05
  • @unicorn2 I use InProc as my session state – Alvin Stefanus Dec 23 '16 at 05:03
  • could you please post code how you initialize your `dbPages` context? and how you reading your connection string? – madoxdev Dec 23 '16 at 09:14
  • SQL Server Error 26 usually means wrong DB configuration/connection string or TCP port 1433 issue, but sometimes hides another error behind it (including cookie value problems). Since incognito mode won't share existing cookies stored in browser, it may related to how `ASP.NET_SessionId` cookie was handled in different browser modes. – Tetsuya Yamamoto Dec 23 '16 at 09:38
  • Sorry ...Have you tried to open a page of the site after server restart .. if it works .. you can set the application pool and site settings to do this for you ... – federico scamuzzi Dec 29 '16 at 08:34

4 Answers4

1

I think, this will help you in setting up an event that is fired every time App pool recyles and then this will help you to expire all the cookies inside that event.

Community
  • 1
  • 1
Rachit Pandey
  • 346
  • 2
  • 12
1

The AntiForgeryToken (stored in a hidden field) will change after app restart, so all values used from the previous app session (already loaded in your HTML in the browser) are obsolete. You need to refresh the page after app start to get the new token value, or else all ajax calls will be refused! Also there is a cookie named "__RequestVerificationToken" that is used to store that value, you need to remove that one too if exists.

0

Since you are having a problem with cookies you can use this is a way to clear all cookies

string[] myCookies = Request.Cookies.AllKeys;
foreach (string cookie in myCookies)
{
  Response.Cookies[cookie].Expires = DateTime.Now.AddDays(-1);
}

You could call that when you call HttpRuntime.UnloadAppDomain()

An cookies survive because they are not on the server side ;-)

Mauricio Gracia Gutierrez
  • 10,288
  • 6
  • 68
  • 99
0

The fault was because the cookie is not invalidated after server restart.

So this is what I do:

Everytime the server restart, the server creates a cookie which hold the time of the application being started, then pass it to all the users.

In Global.asax "Application_BeginRequest" the cookie which hold the application starting time is checked, if the cookie hold the earlier time, then:

WebSecurity.Logout();
Roles.DeleteCookie();

to remove all the troubling cookies. After that the user is redirected to the login page.

Alvin Stefanus
  • 1,873
  • 2
  • 22
  • 60