【问题标题】:Create the own VirtualPathProvider in MVC4?在 MVC4 中创建自己的 VirtualPathProvider?
【发布时间】:2012-12-17 13:14:07
【问题描述】:

我很难从图书馆获取一些视图到主项目。我开始在这里阅读有关创建自己的 VirtualPathProvider 实现的信息:Using VirtualPathProvider to load ASP.NET MVC views from DLLs

我必须设置我的视图 = EmbbebedResource 才能从库中获取资源。但是现在又抛出一个错误。

在我的部分视图的标题中,我有以下内容:

@model Contoso.ExercisesLibrary.AbsoluteArithmetic.Problem1

错误提示:外部组件已引发异常。 c:\Users\Oscar\AppData\Local\Temp\Temporary ASP.NET Files\root\4f78c765\7f9a47c6\App_Web_contoso.exerciseslibrary.absolutearithmetic.view1.cshtml.38e14c22.y-yjyt6g.0.cs(46):错误 CS0103 : 当前上下文中不存在名称“模型”

我不知道为什么编译器会告诉我无法识别我的模型。当我处于设计模式时,我可以看到编译器检查一切正常。

查看图片

我做错了什么或者我错过了什么? 提前致谢。

【问题讨论】:

  • 你找到解决办法了吗?
  • @SanjaMelnichuk 没有人!
  • 我找到了,如果有趣我可以发布它
  • 是的,当然......我真的找不到好的解决方案,当时我不得不选择另一个替代方案

标签: asp.net asp.net-mvc razor asp.net-mvc-4 partial-views


【解决方案1】:

我和你有同样的问题,所以在所有搜索之后我得到了有效的解决方案

创建您自己的基于 WebViewPage 的抽象类(模型通用和非通用)

public abstract class MyOwnViewPage<TModel> : WebViewPage<TModel> { }

public abstract class MyOwnViewPage : WebViewPage {   }

接下来创建基于 VirtualFile 的类或嵌入视图的

class AssemblyResourceFile : VirtualFile
    {
        private readonly IDictionary<string, Assembly> _nameAssemblyCache;
        private readonly string _assemblyPath;
        private readonly string _webViewPageClassName;
        public string LayoutPath { get; set; }
        public string ViewStartPath { get; set; }

        public AssemblyResourceFile(IDictionary<string, Assembly> nameAssemblyCache, string virtualPath) :
            base(virtualPath)
        {
            _nameAssemblyCache = nameAssemblyCache;
            _assemblyPath = VirtualPathUtility.ToAppRelative(virtualPath);
            LayoutPath = "~/Views/Shared/_Layout.cshtml";
            ViewStartPath = "~/Views/_ViewStart.cshtml";
            _webViewPageClassName = typeofMyOwnViewPage).ToString();
        }

        // Please change Open method for your scenario
        public override Stream Open()
        {
            string[] parts = _assemblyPath.Split(new[] { '/' }, 4);    

            string assemblyName = parts[2];
            string resourceName = parts[3].Replace('/', '.');

            Assembly assembly;

            lock (_nameAssemblyCache)
            {
                if (!_nameAssemblyCache.TryGetValue(assemblyName, out assembly))
                {
                    var assemblyPath = Path.Combine(HttpRuntime.BinDirectory, assemblyName);
                    assembly = Assembly.LoadFrom(assemblyPath);

                    _nameAssemblyCache[assemblyName] = assembly;
                }
            }

            Stream resourceStream = null;

            if (assembly != null)
            {
                 resourceStream = assembly.GetManifestResourceStream(resourceName);

                if (resourceName.EndsWith(".cshtml"))
                {
                    //the trick is here. We must correct our embedded view
                    resourceStream = CorrectView(resourceName, resourceStream);
                }
            }

            return resourceStream;
        }

        public Stream CorrectView(string virtualPath, Stream stream)
        {
            var reader = new StreamReader(stream, Encoding.UTF8);
            var view = reader.ReadToEnd();
            stream.Close();
            var ourStream = new MemoryStream();
            var writer = new StreamWriter(ourStream, Encoding.UTF8);

            var modelString = "";
            var modelPos = view.IndexOf("@model");
            if (modelPos != -1)
            {
                writer.Write(view.Substring(0, modelPos));
                var modelEndPos = view.IndexOfAny(new[] { '\r', '\n' }, modelPos);
                modelString = view.Substring(modelPos, modelEndPos - modelPos);
                view = view.Remove(0, modelEndPos);
            }

            writer.WriteLine("@using System.Web.Mvc");
            writer.WriteLine("@using System.Web.Mvc.Ajax");
            writer.WriteLine("@using System.Web.Mvc.Html");
            writer.WriteLine("@using System.Web.Routing");

            var basePrefix = "@inherits " + _webViewPageClassName;

            if (virtualPath.ToLower().Contains("_viewstart"))
            {
                writer.WriteLine("@inherits System.Web.WebPages.StartPage");
            }
            else if (modelString == "@model object")
            {
                writer.WriteLine(basePrefix + "<dynamic>");
            }
            else if (!string.IsNullOrEmpty(modelString))
            {
                writer.WriteLine(basePrefix + "<" + modelString.Substring(7) + ">");
            }
            else
            {
                writer.WriteLine(basePrefix);
            }


            writer.Write(view);
            writer.Flush();
            ourStream.Position = 0;
            return ourStream;
        }
    }

接下来创建基于 VirtualPathProvider 的类(根据您的目的对其进行修改)

public class AssemblyResPathProvider : VirtualPathProvider
    {
        private readonly Dictionary<string, Assembly> _nameAssemblyCache;

        private string _layoutPath;
        private string _viewstartPath;

        public AssemblyResPathProvider(string layout, string viewstart)
        {
            _layoutPath = layout;
            _viewstartPath = viewstart;

            _nameAssemblyCache = new Dictionary<string, Assembly>(StringComparer.InvariantCultureIgnoreCase);
        }

      private bool IsAppResourcePath(string virtualPath)
        {
            string checkPath = VirtualPathUtility.ToAppRelative(virtualPath);



            bool bres1 = checkPath.StartsWith("~/App_Resource/",
                                         StringComparison.InvariantCultureIgnoreCase);


            bool bres2 = checkPath.StartsWith("/App_Resource/",
                                         StringComparison.InvariantCultureIgnoreCase);

        //todo: fix this    
            if (checkPath.EndsWith("_ViewStart.cshtml"))
            {
                return false;
            }

            if (checkPath.EndsWith("_ViewStart.vbhtml"))
            {
                return false;
            }

            return ((bres1 || bres2));

        }

        public override bool FileExists(string virtualPath)
        {
            return (IsAppResourcePath(virtualPath) ||
                    base.FileExists(virtualPath));
        }


        public override VirtualFile GetFile(string virtualPath)
        {
            if (IsAppResourcePath(virtualPath))
            {
        // creating AssemblyResourceFile instance
                return new AssemblyResourceFile(_nameAssemblyCache, virtualPath,_layoutPath,virtualPath);
            }

            return base.GetFile(virtualPath);
        }

        public override CacheDependency GetCacheDependency(
            string virtualPath,
            IEnumerable virtualPathDependencies,
            DateTime utcStart)
        {
            if (IsAppResourcePath(virtualPath))
            {
                return null;
            }

            return base.GetCacheDependency(virtualPath,
                                           virtualPathDependencies, utcStart);
        }

    }

最后在 global.asax 中注册您的 AssemblyResPathProvider

string  _layoutPath = "~/Views/Shared/_Layout.cshtml";
string  _viewstarPath = "~/Views/_ViewStart.cshtml";
HostingEnvironment.RegisterVirtualPathProvider(new AssemblyResPathProvider(_layoutPath,_viewstarPath));

这不是理想的解决方案,但它对我很有用。干杯!

【讨论】:

    【解决方案2】:

    我遇到了这个问题“当前上下文中不存在名称‘模型’”。我所做的是将相同的“区域”文件夹结构(来自我的嵌入式 mvc 项目)添加到我的主 MVC 项目(Areas/AnualReports/Views/)并复制 web.config(默认 web.config 来自视图文件夹,而不是来自根目录的那个) ) 到解决问题的 Views 文件夹。我不确定这是否适用于您的情况。

    更新: 将 web.config(来自视图文件夹)添加到主 MVC 项目中的根“区域”文件夹也可以。

    【讨论】:

      【解决方案3】:

      就我而言,解决方案是让虚拟路径以“~Views/”开头 - 就像任何普通视图一样。

      不工作:~/VIRTUAL/Home/Index.cshtml
      工作:~/Views/VIRTUAL/Home/Index.cshtml

      我认为,这与位于 ~/Views 中的 web.config 并为视图定义了很多东西有关。也许任何人都可以提供更多信息。

      希望对您有所帮助。

      【讨论】:

        【解决方案4】:

        尝试将@inherits 指令添加到剃刀视图的顶部:

        @inherits System.Web.Mvc.WebViewPage
        @model Contoso.ExercisesLibrary.AbsoluteArithmetic.Problem1
        

        您需要这个的原因是因为您的视图来自嵌入式资源,而不是来自标准的~/Views 位置。如您所知,在~/Views 内部有一个名为 web.config 的文件。在这个文件中有一个pageBaseType="System.Web.Mvc.WebViewPage" 指令,指示~/Views 中的所有Razor 文件都应该从这个基类型继承。但是由于您的视图现在来自未知位置,因此您没有指定它应该是System.Web.Mvc.WebViewPage。并且所有 MVC 特定的东西,例如模型、HTML 帮助器……都在这个基类中定义。+

        【讨论】:

        • 嗨达林,我遇到了和达夫一样的问题。不幸的是,您添加 @inherits 的提示并没有解决它(但对我来说很有意义)。还有什么解决办法?
        • 对不起,我不知道。当我需要使用嵌入在其他项目中的 Razor 视图时,这一直对我有用。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-04
        • 2021-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多