2

I need to be able to return partial view as string in my MVC app via signalR. I'm using hubs.

I'm using the following method to return a partial view string (from here):

    public static string RenderPartialView(string controllerName, string partialView, object model)
    {
        var context = httpContextBase as HttpContextBase;

        var routes = new RouteData();
        routes.Values.Add("controller", controllerName);

        var requestContext = new RequestContext(context, routes);

        string requiredString = requestContext.RouteData.GetRequiredString("controller");
        var controllerFactory = ControllerBuilder.Current.GetControllerFactory();
        var controller = controllerFactory.CreateController(requestContext, requiredString) as ControllerBase;

        controller.ControllerContext = new ControllerContext(context, routes, controller);

        var ViewData = new ViewDataDictionary();

        var TempData = new TempDataDictionary();

        ViewData.Model = model;

        using (var sw = new StringWriter())
        {
            var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, partialView);
            var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, ViewData, TempData, sw);

            viewResult.View.Render(viewContext, sw);
            return sw.GetStringBuilder().ToString();
        }
    }

In order for this method to work I need HttpContext.Current therefore in my OnConnected (I noticed that this always exists) I set it like so:

    public class TaskActionStatus : Hub
    {
        private static HttpContextBase httpContextBase;
...

        public override Task OnConnected()
        {
            httpContextBase = new HttpContextWrapper(HttpContext.Current) as HttpContextBase;
...

and then I use it in my RenderPartialView method:

var context = httpContextBase as HttpContextBase;

This way I always have access to current HttpContext. However, I noticed that sometimes my static copy of HttpContext is null. Why is that?.

  • What's the best approach here?
  • Is there a way to render partial view without HttpContext?
Community
  • 1
  • 1
ShaneKm
  • 20,823
  • 43
  • 167
  • 296
  • You don't return views from a hub, if you need to then you're doing something wrong. – davidfowl Apr 02 '13 at 17:07
  • i'm not returning views. I'm returning a string. (view to string) – ShaneKm Apr 03 '13 at 06:55
  • And you're trying to call into the mvc pipeline from SingalR? – davidfowl Apr 03 '13 at 08:19
  • yes. i'm trying to generate partial view as string and send that string to signalR clients via hub. – ShaneKm Apr 05 '13 at 05:03
  • 1
    I'm learning signalr by making a card game with it.. Because hubs behave very similarly to controllers, it was my instinct to try and return a view from my hub as well. You really should not try and hack into the mvc pipeline to do this. you will encounter horrible problems. what you should do instead is pass the data that you need from your hub to your client, and then have your client call the controller with ajax. maybe that won't fit exactly to your scenario, but maybe that can help get you on the right track. – Donuts Apr 14 '14 at 09:11

1 Answers1

1

I used fake http context to generate view:

    public static string GetRazorViewAsString(object model, string filePath)
    {
        HttpContext httpContext = MockHelper.FakeHttpContext();

        var st = new StringWriter();
        var context = new HttpContextWrapper(httpContext);

        var routeData = new RouteData();
        var controllerContext = new ControllerContext(new RequestContext(context, routeData), new FakeController());
        var razor = new RazorView(controllerContext, filePath, null, false, null);
        razor.Render(
            new ViewContext(controllerContext, razor, new ViewDataDictionary(model), new TempDataDictionary(), st), 
            st);
        return st.ToString();
    }

    #endregion
}

public class FakeController : Controller
{
}

public class MockHelper
{
    #region Public Methods and Operators

    public static HttpContext FakeHttpContext()
    {
        var httpRequest = new HttpRequest(string.Empty, "http://novomatic/", string.Empty);
        var stringWriter = new StringWriter();
        var httpResponce = new HttpResponse(stringWriter);
        var httpContext = new HttpContext(httpRequest, httpResponce);

        var sessionContainer = new HttpSessionStateContainer(
            "id", 
            new SessionStateItemCollection(), 
            new HttpStaticObjectsCollection(), 
            10, 
            true, 
            HttpCookieMode.AutoDetect, 
            SessionStateMode.InProc, 
            false);

        httpContext.Items["AspSession"] =
            typeof(HttpSessionState).GetConstructor(
                BindingFlags.NonPublic | BindingFlags.Instance, 
                null, 
                CallingConventions.Standard, 
                new[] { typeof(HttpSessionStateContainer) }, 
                null).Invoke(new object[] { sessionContainer });

        return httpContext;
    }

    #endregion
}
ShaneKm
  • 20,823
  • 43
  • 167
  • 296