c# - ASP.NET MVC: Views using a model type that is loaded by MEF can't be found by the view engine -


i'm attempting create framework allowing controllers , views dynamically imported mvc application. here's how works far:

  • i'm using .net 4, asp.net mvc 3 rc , razor viewengine
  • controllers exported , imported using mef per project - call set of controllers , views given project "module"
  • assemblies discovered using mef dynamically referenced buildmanager using pre-application start method , buildmanager.addreferencedassembly.
  • binaries (from exporting project) , views copied target project's folder structure using build event
  • controllers selected using custom controller factory inherits defaultcontrollerfactory , overrides getcontrollertype()
  • views selected using custom view engine inherits razorviewengine , overrides getview() , getpartialview() allow views in module-specific view directories

everything works far except views using typed model. views use dynamic model work fine, when specify model type using @model, ysod says "the view 'index' or master not found".

when debugging viewengine implementation, can see that: this.virtualpathprovider.fileexists(string.format(this.viewlocationformats[2], viewname, controllercontext.routedata.getrequiredstring("controller"))) returns true, while

this.fileexists(controllercontext, string.format(this.viewlocationformats[2], viewname, controllercontext.routedata.getrequiredstring("controller"))) returns false.

looking in reflector, razorviewengine implementation of fileexists() winds doing this:

return (buildmanager.getobjectfactory(virtualpath, false) != null); 

however, can't view buildmanager.getobjectfactory() reflector because it's hidden somehow.

i'm suspecting has fact model type type loaded mef, since i'm referencing assemblies discovered mef buildmanager, i'm out of leads. can provide little more insight might going on?


update: turns out using outdated version of reflector before .net 4. can see getobjectfactory() now, can't seem find helpful. i've tried adding findview() overload:

try { var path = string.format(this.viewlocationformats[2], viewname, controllercontext.routedata.getrequiredstring("controller")); var objfactory = system.web.compilation.buildmanager.getobjectfactory(virtualpath: path, throwifnotfound: true); } catch { }

unfortunately, objfactory ends null, , no exception gets thrown. bits deal compilation errors part of private methods or types can't debug of that, seems they'd end throwing exception, doesn't seem happening. looks i'm @ dead end again. help!


update 2

i've discovered @ point findview() being called, if call appdomain.currentdomain.getassemblies(), assembly model type in is included. however, cannot load type using type.gettype().


update 3

here's i'm seeing: not found



update 4

here's viewengine implementation:

using system; using system.linq; using system.web.mvc; using system.web.hosting; using system.web.compilation;  namespace site.admin.portal {     public class moduleviewengine : razorviewengine     {         private static readonly string[] viewlocationformats = new string[]         {             "~/views/{0}/{{1}}/{{0}}.aspx",             "~/views/{0}/{{1}}/{{0}}.ascx",             "~/views/{0}/{{1}}/{{0}}.cshtml",             "~/views/{0}/shared/{{0}}.aspx",             "~/views/{0}/shared/{{0}}.ascx",             "~/views/{0}/shared/{{0}}.cshtml"         };          public moduleviewengine(imodule module)         {             this.module = module;             var formats = viewlocationformats.select(f => string.format(f, module.name)).toarray();              this.viewlocationformats = formats;             this.partialviewlocationformats = formats;             this.areaviewlocationformats = formats;             this.areapartialviewlocationformats = formats;             this.areamasterlocationformats = formats;         }          public imodule module { get; private set; }          public override viewengineresult findpartialview(controllercontext controllercontext, string partialviewname, boolean usecache)         {             var modulename = controllercontext.routedata.getrequiredstring("module");             if (modulename.equals(this.module.name, stringcomparison.invariantcultureignorecase))             {                 return base.findpartialview(controllercontext, partialviewname, usecache);             }             else return new viewengineresult(new string[0]);         }          public override viewengineresult findview(controllercontext controllercontext, string viewname, string mastername, boolean usecache)         {             var modulename = controllercontext.routedata.getrequiredstring("module");             if (modulename.equals(this.module.name, stringcomparison.invariantcultureignorecase))             {                 var baseresult = base.findview(controllercontext, viewname, mastername, usecache);                 return baseresult;             }             else return new viewengineresult(new string[0]);         }             } } 

based on update 2, i'm guessing you've got explicitly loaded copy of assembly (that is, loaded through other method load, loadfrom). explicitly loaded assemblies set off aside special place, because not allowed satisfy implicit type requirements. rules fusion (the assembly loader) can pretty arcane , hard understand.

i agree matthew's assessment that, work, dll going have in /bin or else never able satisfy implicit type requirement.


Comments

Popular posts from this blog

asp.net - repeatedly call AddImageUrl(url) to assemble pdf document -

java - Android recognize cell phone with keyboard or not? -

iphone - How would you achieve a LED Scrolling effect? -