我正在尝试在我的控制器和我的视图之间创建另一个层,以便我可以根据用户的“客户端ID”将不同版本的视图传递给用户。
我有以下代码:
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
// set client
var client = new Client();
client.Id = Guid.NewGuid();
client.Name = "Foo";
// set user
var user = new User();
user.Id = Guid.NewGuid();
user.ClientId = client.Id;
user.Name = "Foo";
return ViewRenderer.RenderView("AddComplete", client);
}
}
我的ViewRenderer类如下所示:
public static class ViewRenderer
{
public static ViewResult RenderView(string view, Guid clientId)
{
string viewName = GetViewForClient(view, clientId);
return Controller.View(view);
}
public static string GetViewForClient(string view, Guid clientId)
{
// todo: logic to return view specific to the company to which a user belongs...
}
}
问题是,return Controller.View(view);
中的行RenderView(string view, Guid clientId)
给了我错误:
System.Web.Mvc.Controller.View()'因其无法访问 保护水平
我很想知道如何解决这个错误,或者是否有更好的方法来做我想做的事情,即显示不同版本的视图,这些版本特定于用户所属的公司所属
编辑:我在脑海中挣扎的另一种选择......
是否有办法覆盖View()
方法,以便我可以在其前面加上目录名,例如,属于“Acme Co.”的用户将调用与View("MyView")
之类的其他所有人相同的控制器操作,但该方法实际上将调用View("AcmeCo/MyView")
但是,我实际上并没有在我的控制器中编写该代码,它只是从用户的客户端ID属性派生的
答案 0 :(得分:3)
您只需替换视图引擎,而不是添加其他抽象。
编写自己的View引擎(以下是如何从RazorViewEngine开始)
public class ByIdRazorViewEngine : RazorViewEngine
{
protected override IView CreateView(ControllerContext controllerContext,
string viewPath, string masterPath)
{
var id = // get something from controller context controllerContext
var newViewPath = CalculateViewPathFromId(id);
return base.CreateView(controllerContext, newViewPath, masterPath);
}
并在Global.asax.cs
注册:
protected void Application_Start()
{
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new ByIdRazorViewEngine());
}
答案 1 :(得分:2)
View()
方法是受保护的成员。您只能从派生类型(例如HomeController
类)中访问它。另外,您尝试以静态方式访问它。
您可以创建一个公开您的专用视图逻辑的基本控制器。为了便于说明,我将其称为DynamicViewControllerBase
public class HomeController : DynamicViewControllerBase
{
//
// GET: /Home/
public ActionResult Index()
{
// set client
var client = new Client();
client.Id = Guid.NewGuid();
client.Name = "Foo";
// set user
var user = new User();
user.Id = Guid.NewGuid();
user.ClientId = client.Id;
user.Name = "Foo";
return RenderView("AddComplete", client);
}
}
public class DynamicViewControllerBase : Controller
{
protected ViewResult RenderView(string view, Guid clientId)
{
string viewName = GetViewForClient(view, clientId);
return View(view);
}
// Unless you plan to use methods and properties within
// the instance of `Controller`, you can leave this as
// a static method.
private static string GetViewForClient(string view, Guid clientId)
{
// todo: logic to return view...
}
}
答案 2 :(得分:1)
如果您想拥有的是控制器前面的公司名称,请将RoutePrefix
属性应用于您的控制器。
示例:
[RoutePrefix(@"{company}")]
public partial class HomeController : Controller
{
}
在你的RouteConfig文件中,
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// Make sure this line is added
routes.MapMvcAttributeRoutes();
}
由于您的用户必须通过身份验证才能登录自己的帐户,因此一旦他们对自己进行了身份验证,您就可以:
获得公司名称后,您可以构建具有该名称的网址。
示例:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginViewModel model)
{
// ... authenticate user etc
// Redirect to
// foo.com/abc/home
return this.RedirectToAction("Index", "Home", new { company = "abc" });
}
如果您正试图解决这个问题,我怀疑您是否能够首先通过路线获取Web请求,并且路由决定执行哪个控制器/操作,但是知道您的行动需要执行以检索的公司名称。