I am trying to dynamically load DLLs and I am facing the following issues:
The Resources in the dynamically loaded DLLs are not working. It is picking the neutral culture which is English, and no other .resx files are getting called.
I am unable to call a WCF service in the dynamically loaded DLLs.
For 2) I have a work around but for 1) I am still stuck.
The technology i am using is. Net 4.0(with MEF)
I found an alternate solution for 1).
It was my mistake only, the resources DLLs were being picked from the wrong path.
Related
We are developing a web application which has tons of plugin dll files.
Now, we are able to load all the assemblies we need but we are using BuildManager.AddReferencedAssembly while doing this. Which - I guess - causes a little problem.
The problem is, we need to update these dll files without restarting the application but these dll files are locked while application is running.
We are not using bin folder for these dll files. We are using 2 different folders (first one - ~/plugins - for copying files by us, second - ~/ptemp - folder is used for copying the files located under plugins folder and then loading in application like ones in bin folder)
As you know while application is working, you can overwrite the files in bin folder, so it means that it is possible to overwrite project assemblies while application is running.
After some research I found that it is possible by using private folder stuff in appdomainsetup but couldn't figure out how. (we dont want to create another appdomain, we want these files located in ptemp folder to be attached to main domain)
Sorry about my poor english but if you can, please help us.
By the way, some of these dll files includes some mvc areas.
We are using .Net 4.5, Mvc 4.
If it is necessary, I can post some code.
Here is what we are doing:
var shadowCopyDirectories = AppDomain.CurrentDomain.SetupInformation.ShadowCopyDirectories;
var newShadowCopyDirectories = shadowCopyDirectories
+ System.IO.Path.PathSeparator
+ HostingEnvironment.MapPath("~/App_Data/DynamicAssemblies/");
#pragma warning disable 618
// Disabled compiler warning
AppDomain.CurrentDomain.SetShadowCopyPath(newShadowCopyDirectories);
#pragma warning restore 618
Basicly enables shadow copying of assemblies in the given directory to Temporary ASP.NET Files which means that those assemblies will not be locked. Have tried finding the non obsolete way of doing this but after searching for like 30 minutes I came up empty and didnt have the time to search further.
Still you can not avoid an application restart because:
1) You can not unload the 'old' assemblies from the currently running application, which means you are gonna be left with junk in memory and can face a kind of dll hell by having loaded two versions of the same assembly (e.x. Type A originates from Assembly 1 while Type B originates from assembly B)
2) You need a way to tell the BuildManager to recompile everything
But in the end you are probably better off enabling shadow copying because when recycling, a second worker process might be spawned while the first one waits until the second one is ready in which case you will not be able to update those 'dynamic' assemblies until you completely stop your application pool.
It seems that the best way to do this is an application restart
I'm trying to write a module/plugin system for a website I'm working on. The overall goals are:
That the main website does not have to be recompiled every time a new plugin is added.
To be able to dump DLL's and CSHTML files into a set of folders that would basically add a set of routes, controller(s), and any other assemblies that the module depends on (Entity Framework, etc).
To avoid marking plugin files as "embedded resources" -- especially views.
To be able to add and remove these modules/plugins WITHOUT having to restart/recycle the IIS app pool or unload the app domain.
I got #1-3 working by following the example of Umbraco. Basically, I marked a method with the PreApplicationStartMethod attribute, and in it I shadow copy DLLs around, and use a custom ViewEngine to locate the module's CSHTML files. When my website first starts up, my module's controllers and views are working, and assemblies are loaded: Hooray!
However, when it came time to try part #4, I am getting this error when calling BuildManager.AddReferencedAssembly():
This method can only be called during the application's pre-start
initialization phase. Use PreApplicationStartMethodAttribute to
declare a method that will be invoked in that phase
It's been a very frustrating process so far, and my gut tells me that this error signifies a dead end. Is this the case, or is there a clever workaround?
Editing the web.config file when you add the new modules should cause the site to recompile.
You could automate this in a script, forcing your new .dll's to be copied to the live ASP.NET temp files directory.
Check out portable areas. Essentially a regular MVC area (including views, controllers, etc.) gets compiled into a single dll. These dll's (one for each area) can be dropped into a hosting MVC website and can be called like any other MVC area.
Some references to get started:
Portable Areas three years later – Part 5
MvcContrib Portable Areas
"To be able to add and remove these modules/plugins WITHOUT having to restart/recycle the IIS app pool or unload the app domain."
It turns out that this you cannot unload an assembly from an app domain.
How to unload an assembly from the primary AppDomain?
I've got a common Layout.cshtml file that I want to share. When I add the file as a link in the project (via Add Existing Item > Add as Link) I get an error that it cannot be found when I run the application. If I set the build action to "Copy Always" it does copy the file to the build directory, however I still get an error that it cannot find the file (Perhaps I can somehow instruct VS to copy it to the appropriate directory?).
I came across this question: ASP.NET 2 projects to share same files however the answers are pretty complicated and ugly and right now I'm playing around with a lot of different structures and refactoring methods so I don't want to go through some big production just to move a few different files around.
So how can I easily share these kinds of files between the two applications?
Thanks!
You cannot Add as Link static files in an ASP.NET web application. All files need to be included inside this application or when you deploy it in IIS simply won't be able to find any of them. A common technique of sharing static files between multiple web applications is using CDN (Content Delivery Network) where you would host all your static resources (images, CSS, js, ...). For example Google already provides popular frameworks on their CDN.
So for all your custom images you could setup a domain on your web server which will host them all and your web applications will point to this common location. Another advantage of this technique is that clients visiting those applications will already have all static resources in cache.
Looks like it's a bug in msbuild or an unsupported feature. Either way I finally found a workaround published on this guy's blog:
http://consultingblogs.emc.com/jamesdawson/archive/2008/06/03/using-linked-files-with-web-application-projects.aspx
Someone else might give you a better solution, but my approach would be to:
1 - Create a library project
2 - Create a Resources file in the library project
3 - Add the shared resources to the library project.
4 - Compile the library project
5 - Reference the DLL for the library project in the dependent projects
I want to compile App_GlobalResources/Strings.resx into my assembly (and eventually use satellite assemblies for Strings.es.resx, Strings.fr.resx, etc.) but the following error occurs once the app is published:
"Could not load file or assembly 'App_GlobalResources' or one of its dependencies. The system cannot find the file specified."
Steps to Reproduce:
Create a new ASP.NET MVC project.
Add an App_GlobalResources folder and a Strings.resx file.
Set the file's build action to 'Embedded Resource'
Add a string to Strings.resx and use it in HomeController.Index(), e.g. ViewData["Message"] = Strings.MyTest
F5 to debug, works fine.
Publish to IIS and (since Strings.resx is excluded from publishing) you will get the above error in the published site.
Can ASP.NET MVC projects use string resources compiled into the dll and if so, what am I doing wrong?
Update: Here is what I see in Reflector:
So why is the ResourceManager not finding them? Isn't it supposed to fallback to the main assembly by default?
Here's a good starting point http://odetocode.com/Blogs/scott/archive/2009/07/16/resource-files-and-asp-net-mvc-projects.aspx
I setup a project just like you mentioned and got precisely the same error when I deployed to IIS6. Changing Custom Tool to PublicResXFileCodeGenerator and Custom Tool Namespace to Resources per Scott's suggestions cleared it right up.
I'd also follows Scott's lead with respect to eliminating App_GlobalResources but I got it to work just fine. That might be a matter of personal preference.
Probably there is one more thing one should know about the PublicResXFileCodeGenerator - it does not work with files that has more then one dot in the file name (see http://social.msdn.microsoft.com/Forums/ru-RU/9412f049-acd8-4a77-b73a-f3810df18376/naming-resources-files-issue-aspnet-mvc-3?forum=dlr). So the codebehind for the Strings.es.resx, Strings.fr.resx, etc. remains empty. The easy solution is to rename the files.
I want to take a look at my views with reflextor, I have set my project to compile views
<MvcBuildViews>true</MvcBuildViews>
But when opening the DLL for my application in reflextor I do not see the views...
I see the controllers and models but no views...
Have I not compiled the views correctly? or is there more to it?
Thanks,
If you want a fully compiled ASP.NET MVC project with your views compiled, you can either run aspnet_compiler.exe against your web app.
That's the hard way. The easy way is to install the Web Deployment Project add-in to Visual Studio. Then you can add a web deployment project and set it to fully compile your web application.
http://www.microsoft.com/downloads/details.aspx?FamilyId=0AA30AE8-C73B-4BDD-BB1B-FE697256C459&displaylang=en
It's really easy to use and gets you full compilation.
Is there any chance the views are just being compiled in order to provide you with compile time checking but not actually being included in the assembled output?
It seems like the main goal of this feature could be just to help catch compile time errors quicker not necessarily to speed up the processing of the page or anything.
Views are not compiled in DLL, they are copied as is to the output. Attribute that you use is only compile time check for them.