model-view-controllerasp.net-coretempdataasp.net-core-middleware

Access TempData within custom middleware


I have custom middleware that provides global error handling. If an exception is caught it should log the details with a reference number. I then want to redirect the user to an error page and only show the reference number. My research shows that TempData should be ideal for this but it only seems to be accessible from within a controller context. I tried adding the reference number to HttpContext.Items["ReferenceNumber"] = Guid.NewGuid(); But this value is lost through the redirect.

How can middleware pass information through a redirect? Do I just have to put the number in a querystring?


Solution

  • Inside the middleware class you need to add a reference to get access to the required interfaces. I have this middleware in a separate project and needed to add this NuGet package.

    using Microsoft.AspNetCore.Mvc.ViewFeatures;
    

    This then allows you to request the correct services within the middleware.

    //get TempData handle
    ITempDataDictionaryFactory factory = httpContext.RequestServices.GetService(typeof(ITempDataDictionaryFactory)) as ITempDataDictionaryFactory;
    ITempDataDictionary tempData = factory.GetTempData(httpContext);
    

    After you have ITempDataDictionary you can use it like you would use TempData within a controller.

    //pass reference number to error controller
    Guid ReferenceNum = Guid.NewGuid();
    tempData["ReferenceNumber"] = ReferenceNum.ToString();
    
    //log error details
    logger.LogError(eventID, exception, ReferenceNum.ToString() + " - " + exception.Message);
    

    Now when I get the the controller after a redirect I have no issues pulling out the reference number and using it in my view.

    //read value in controller
    string refNum = TempData["ReferenceNumber"] as string;
    if (!string.IsNullOrEmpty(refNum))
        ViewBag.ReferenceNumber = refNum;
    
    @*display reference number if one was provided*@
    @if (ViewBag.ReferenceNumber != null){<p>Reference Number: @ViewBag.ReferenceNumber</p>}
    

    Once you put this all together, you give users a reference number that they can give you to help troubleshoot the problem. But, you are not passing back potentially sensitive error information which could be misused.