문제

별도의 어셈블리를 플러그인할 수 있는 웹 애플리케이션을 만들려고 합니다.저는 종속성 주입을 위해 Unity와 결합된 MVC Preview 4를 사용하고 있는데, 이를 사용하여 플러그인 어셈블리에서 컨트롤러를 생성합니다.저는 뷰 엔진으로 WebForms(기본 aspx)를 사용하고 있습니다.

뷰를 사용하려는 경우 ASPX 부분의 동적 컴파일로 인해 핵심 프로젝트에 정의된 뷰에 갇히게 됩니다.전체 배포 단계를 거치지 않고도 ASPX 파일을 다른 어셈블리에 포함할 수 있는 적절한 방법을 찾고 있습니다.나는 분명한 것을 놓치고 있습니까?아니면 프로그래밍 방식으로 뷰를 생성해야 합니까?


업데이트:허용되는 답변을 변경했습니다.Dale의 답변이 매우 철저함에도 불구하고 저는 다른 가상 경로 제공자를 통해 솔루션을 찾았습니다.그것은 마치 매력처럼 작동하며 코드 전체에서 약 20줄만 사용하면 됩니다.

도움이 되었습니까?

해결책

본질적으로 이것은 사람들이 WebForms를 사용하고 UserControl ASCX 파일을 DLL로 컴파일하려고 시도하는 것과 동일한 문제입니다.나는 이것을 찾았다 http://www.codeproject.com/KB/aspnet/ASP2UserControlLibrary.aspx 그것은 당신에게도 효과가 있을 것입니다.

다른 팁

다양한 부분 샘플에서 이 작업이 제대로 작동하도록 하는 데 너무 오랜 시간이 걸렸습니다. 따라서 일반 Views 폴더와 동일하게 구조화되었지만 모든 항목이 포함된 것으로 빌드되도록 설정된 공유 라이브러리의 Views 폴더에서 보기를 가져오는 데 필요한 전체 코드는 다음과 같습니다. 자원.일반적인 파일이 존재하지 않는 경우에만 포함된 파일을 사용합니다.

Application_Start의 첫 번째 줄:

HostingEnvironment.RegisterVirtualPathProvider(new EmbeddedViewPathProvider());

VirtualPathProvider

   public class EmbeddedVirtualFile : VirtualFile
{
    public EmbeddedVirtualFile(string virtualPath)
        : base(virtualPath)
    {
    }

    internal static string GetResourceName(string virtualPath)
    {
        if (!virtualPath.Contains("/Views/"))
        {
            return null;
        }



        var resourcename = virtualPath
            .Substring(virtualPath.IndexOf("Views/"))
            .Replace("Views/", "OrangeGuava.Common.Views.")
            .Replace("/", ".");

        return resourcename;

    }


    public override Stream Open()
    {
        Assembly assembly = Assembly.GetExecutingAssembly();


        var resourcename = GetResourceName(this.VirtualPath);
        return assembly.GetManifestResourceStream(resourcename);
    }




}

public class EmbeddedViewPathProvider : VirtualPathProvider
{


    private bool ResourceFileExists(string virtualPath)
    {

        Assembly assembly = Assembly.GetExecutingAssembly();


        var resourcename = EmbeddedVirtualFile.GetResourceName(virtualPath);
        var result = resourcename != null && assembly.GetManifestResourceNames().Contains(resourcename);
        return result;
    }

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


    public override VirtualFile GetFile(string virtualPath)
    {

        if (!base.FileExists(virtualPath))
        {
            return new EmbeddedVirtualFile(virtualPath);
        }
        else
        {
            return base.GetFile(virtualPath);
        }

    }

}

이를 작동시키기 위한 마지막 단계는 루트 Web.Config에 강력한 형식의 MVC 보기를 구문 분석하기 위한 올바른 설정이 포함되어야 한다는 것입니다. views 폴더에 있는 보기는 사용되지 않기 때문입니다.

<pages
    validateRequest="false"
    pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
    pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
    userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
  <controls>
    <add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
  </controls>
</pages>

Mono와 함께 작동하려면 몇 가지 추가 단계가 필요합니다.먼저, 필요에 따라가 아니라 앱이 시작될 때 views 폴더의 모든 파일이 로드되므로 GetDirectory를 구현해야 합니다.

public override VirtualDirectory GetDirectory(string virtualDir)
    {
        Log.LogInfo("GetDirectory - " + virtualDir);
        var b = base.GetDirectory(virtualDir);
        return new EmbeddedVirtualDirectory(virtualDir, b);
    }

public class EmbeddedVirtualDirectory : VirtualDirectory
{
    private VirtualDirectory FileDir { get; set; } 

    public EmbeddedVirtualDirectory(string virtualPath, VirtualDirectory filedir)
        : base(virtualPath)
    {
        FileDir = filedir;
    }

    public override System.Collections.IEnumerable Children
    {
        get { return FileDir.Children; }
    }

    public override System.Collections.IEnumerable Directories
    {
        get { return FileDir.Directories; }
    }

    public override System.Collections.IEnumerable Files
    {
        get {

            if (!VirtualPath.Contains("/Views/") || VirtualPath.EndsWith("/Views/"))
            {
                return FileDir.Files;
            }

            var fl = new List<VirtualFile>();

            foreach (VirtualFile f in FileDir.Files)
            {
                fl.Add(f);
            }


            var resourcename = VirtualPath.Substring(VirtualPath.IndexOf("Views/"))
.Replace("Views/", "OrangeGuava.Common.Views.")
.Replace("/", ".");

            Assembly assembly = Assembly.GetExecutingAssembly();

            var rfl = assembly.GetManifestResourceNames()
                .Where(s => s.StartsWith(resourcename))
                .Select(s => VirtualPath + s.Replace(resourcename, ""))
                .Select(s => new EmbeddedVirtualFile(s));
            fl.AddRange(rfl);

            return fl;
        }
    }
}

마지막으로 강력한 형식의 뷰는 거의 완벽하게 작동하지는 않습니다.모델은 유형이 지정되지 않은 객체로 처리되므로 강력한 유형을 다시 얻으려면 다음과 같이 공유 보기를 시작해야 합니다.

<% var Model2 = Model as IEnumerable<AppModel>;  %>
protected void Application_Start()
{
    WebFormViewEngine engine = new WebFormViewEngine();

    engine.ViewLocationFormats = new[] { "~/bin/Views/{1}/{0}.aspx", "~/Views/Shared/{0}.aspx" };
    engine.PartialViewLocationFormats = engine.ViewLocationFormats;

    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(engine);

    RegisterRoutes(RouteTable.Routes);
}

뷰의 '출력에 복사' 속성을 '항상 복사'로 설정하세요.

아직도 성배를 찾고 있는 여러분에게 추가 사항:웹폼 뷰엔진에 너무 집착하지 않는다면 나는 그것을 찾는 데 좀 더 가까워졌습니다.

나는 최근에 Spark 뷰엔진을 시험해 보았습니다.완전히 훌륭하고 위협을 받더라도 웹 양식으로 돌아가지 않을 것이라는 점 외에도 응용 프로그램의 모듈성을 위한 몇 가지 아주 좋은 후크를 제공합니다.문서의 예는 Windsor를 IoC 컨테이너로 사용하는 것이지만 다른 접근 방식을 취하려는 경우 훨씬 더 어려울 것이라고는 상상할 수 없습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top