我希望创建一个可在多个MVC项目之间共享的自定义控件。这个自定义控件只是(在我看来)一个局部视图,在它后面的类中有一个模型和业务逻辑。 MVC网站可以包含对此类库的引用,并在.cshtml
中简单地调用@Html.Partial("CoolControl").
我现在正在尝试的是一个类库项目,其中MVC -> Models folder
包含我的模型代码,而一个Views文件夹包含控件的.cshtml代码。
如果我没记错的话,部分内容会进入MVC网站的Views\Shared
文件夹,以便找到它们。但是,除此之外的部分生活。
如何告诉MVC在外部库中查看部分视图?这甚至是最好的方法吗?
在MVC中创建可移植控件有更好的方法吗?
答案 0 :(得分:1)
在类库中共享多个项目的部分视图并不那么简单。 首先,您需要创建虚拟文件和虚拟提供程序
public class AspNetVirtualFile : VirtualFile
{
private string path;
public AspNetVirtualFile(string virtualPath)
: base(virtualPath)
{
path = VirtualPathUtility.ToAppRelative(virtualPath);
}
public override System.IO.Stream Open()
{
var parts = path.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
var assemblyName = parts[2];
var resourceName = parts[3];
assemblyName = Path.Combine(HttpRuntime.BinDirectory, assemblyName);
var assembly = Assembly.LoadFile(assemblyName + ".dll");
if (assembly != null)
{
return assembly.GetManifestResourceStream(resourceName);
}
return null;
}
}
VirtualProvider
public class AspNetVirtualProvider : VirtualPathProvider
{
public const string StartPath = "~/UserControls/";
public const string Path = "~/UserControls/{0}/{1}";
public AspNetVirtualProvider() { }
private bool IsEmbeddedResourcePath(string virtualPath)
{
try
{
var checkPath = VirtualPathUtility.ToAppRelative(virtualPath);
return checkPath.StartsWith(StartPath, StringComparison.InvariantCultureIgnoreCase);
}
catch
{
}
return false;
}
public override bool FileExists(string virtualPath)
{
return IsEmbeddedResourcePath(virtualPath) || base.FileExists(virtualPath);
}
public override VirtualFile GetFile(string virtualPath)
{
if (IsEmbeddedResourcePath(virtualPath))
{
return new AspNetVirtualFile(virtualPath);
}
else
{
return base.GetFile(virtualPath);
}
}
public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart)
{
if (IsEmbeddedResourcePath(virtualPath))
{
return null;
}
else
{
return base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
}
}
}
看到提供程序将在该共享.dll中的UserControls文件夹中找到文件,您可以根据需要进行更改。 在Global.asax Application_Start中:
System.Web.Hosting.HostingEnvironment.RegisterVirtualPathProvider(new AspNetVirtualProvider());
创建一个HtmlHelper,别忘了使用System.Web.Mvc.Html:
public static class HtmlHelpers
{
public static void SharedRenderPartial(this HtmlHelper h, string assemblyName, string fileName, object model)
{
h.RenderPartial(String.Format(AspNetVirtualProvider.Path, assemblyName, fileName), model);
}
}
现在,您可以在自己的视图中执行以下操作:
@{ Html.SharedRenderPartial("My.Qualified.Assembly", String.Format("My.Qualified.Assembly.UserControls.{0}", "_ViewName.cshtml"), Model); }
现在,您在My.Qualified.Assembly项目的UserControls文件夹中创建了一个cshtml,您需要将文件BuildAction更改为EmbededResource。在你的视图中,你需要明确地添加using和@inherits System.Web.Mvc.WebViewPage。
答案 1 :(得分:0)
我认为创建类库不是创建自定义控件的好方法。创建nuget package会更好。它允许您向项目文件夹添加一些其他文件,并解决依赖关系和控件的未来更新问题。
如果您想要搜索与默认文件夹不同的PartialViews
,则最佳解决方案将从RazorViewEngine
继承,创建您自己的路由并在MVC ViewEngines
中注册。这是good article如何做到的。