MVC 5 - 如何创建便携式自定义控件(部分)

时间:2015-03-24 11:37:43

标签: asp.net-mvc razor

我希望创建一个可在多个MVC项目之间共享的自定义控件。这个自定义控件只是(在我看来)一个局部视图,在它后面的类中有一个模型和业务逻辑。 MVC网站可以包含对此类库的引用,并在.cshtml中简单地调用@Html.Partial("CoolControl").

我现在正在尝试的是一个类库项目,其中MVC -> Models folder包含我的模型代码,而一个Views文件夹包含控件的.cshtml代码。

如果我没记错的话,部分内容会进入MVC网站的Views\Shared文件夹,以便找到它们。但是,除此之外的部分生活。

如何告诉MVC在外部库中查看部分视图?这甚至是最好的方法吗?

在MVC中创建可移植控件有更好的方法吗?

2 个答案:

答案 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如何做到的。