Render MVC PartialView в ответ SignalR
Я хотел бы сделать PartialView для строки HTML, чтобы я мог вернуть его в запрос ajax SignalR.
Что-то вроде:
Контактор SignalR (mySignalHub.cs)
public class mySignalRHub: Hub
{
public string getTableHTML()
{
return PartialView("_MyTablePartialView", GetDataItems()) // *How is it possible to do this*
}
}
Razor PartialView (_MyTablePartialView.cshtml)
@model IEnumerable<DataItem>
<table>
<tbody>
@foreach (var dataItem in Model)
{
<tr>
<td>@dataItem.Value1</td>
<td>@dataItem.Value2</td>
</tr>
}
</tbody>
</table>
HTML (MySignalRWebPage.html)
<Script>
...
//Get HTML from SignalR function call
var tableHtml = $.connection.mySignalRHub.getTableHTML();
//Inject into div
$('#tableContainer).html(tableHtml);
</Script>
<div id="tableContainer"></div>
Моя проблема в том, что я не могу показать PartialView вне контроллера. Возможно ли даже сделать PartialView вне контроллера? Было бы очень приятно, что все еще можно использовать потрясающие возможности генерации HTML, которые поставляются с Razor.
Неужели я все это делаю неправильно? Есть ли другой способ?
Ответы
Ответ 1
Вот, что я использую в контроллерах для ajax, я немного изменил его, чтобы его можно было вызывать из метода вместо контроллера, метод returnView
отображает ваше представление и возвращает строку HTML, чтобы вы могли вставить его с помощью JS/jQuery на вашу страницу, когда вы ее получите на стороне клиента:
public static string RenderPartialToString(string view, object model, ControllerContext Context)
{
if (string.IsNullOrEmpty(view))
{
view = Context.RouteData.GetRequiredString("action");
}
ViewDataDictionary ViewData = new ViewDataDictionary();
TempDataDictionary TempData = new TempDataDictionary();
ViewData.Model = model;
using (StringWriter sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(Context, view);
ViewContext viewContext = new ViewContext(Context, viewResult.View, ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}
//"Error" should be name of the partial view, I was just testing with partial error view
//You can put whichever controller you want instead of HomeController it will be the same
//You can pass model instead of null
private string returnView()
{
var controller = new HomeController();
controller.ControllerContext = new ControllerContext(HttpContext,new System.Web.Routing.RouteData(), controller);
return RenderPartialToString("Error", null, new ControllerContext(controller.Request.RequestContext, controller));
}
Я не тестировал его на концентраторе, но он должен работать.
Ответ 2
Вероятно, лучший выбор - использовать RazorEngine, а Wim предлагает.
public class mySignalRHub: Hub
{
public string getTableHTML()
{
var viewModel = new[] { new DataItem { Value1 = "v1", Value2 = "v2" } };
var template = File.ReadAllText(Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
@"Views\PathToTablePartialView\_MyTablePartialView.cshtml"));
return Engine.Razor.RunCompile(template, "templateKey", null, viewModel);
}
}
Ответ 3
В дополнение к ответу, предоставленному мной @user1010609 выше, я тоже справился с этим, и у меня получилась функция, которая возвращает рендер PartialView с указанием имени контроллера, пути к представлению и модели.
Принимает во внимание тот факт, что у вас нет контроллера и, следовательно, ни одно из обычного состояния не поступает из события SignalR.
public static string RenderPartialView(string controllerName, string partialView, object model)
{
var context = new HttpContextWrapper(System.Web.HttpContext.Current) as HttpContextBase;
var routes = new System.Web.Routing.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();
}
}
Вы бы назвали это с чем-то похожим на:
RenderPartialView("MyController", "~/Views/MyController/_partialView.cshtml", model);
Ответ 4
Думали ли вы об использовании механизма шаблонов бритвы, например http://razorengine.codeplex.com/?
Вы не можете использовать его для разбора частичных представлений, но вы можете использовать его для разбора шаблонов бритвы, которые почти похожи на частичные виды.
Ответ 5
Как использовать RazorEngineHost
и RazorTemplateEngine
. Я нашел эту , которая может быть тем, что вы ищете. Это о размещении Razor вне ASP.NET(MVC).
Ответ 6
Основываясь на ответах, поставленных на аналогичный вопрос ниже, я бы предложил использовать
Html.Partial(partialViewName)
Он возвращает MvcHtmlString, который вы можете использовать в качестве содержимого вашего сигнала SignalR. Однако я не тестировал это.
Вопрос: Можно ли визуализировать представление вне контроллера?