I was studying for EPiServer exam and have read this article about EPiServer initialization:
http://world.episerver.com/Documentation/Items/Tech-Notes/EPiServer-CMS-6/EPiServer-CMS-60/Initialization/
It describes how to configure initialization to limit assemblies to be scanned during startup, but there is mentioned forceBinFolderScan attribute which is not described. Examples has it always set to true.
I also found another article which describes how to improve startup time of EPiServer site:
http://world.episerver.com/Blogs/Alexander-Haneng/Dates/2011/12/Starting-CMS-6-R2-sites-faster-after-build/
Author says to change that attribute to false, but doesn't explain what it means. Does setting it to false stops scanning assemblies at all or scans them only at some conditions?
I have quite large site and it takes several minutes to load. I have lot of assemblies in bin folder, so wanted to limit scanning only to those which contains some initialization modules or plugins.
Because of Asp.Net build system and app startup optimization algorithms all assemblies may not be loaded in app domain. This may hide some assemblies from EPiServer initialization system which is executed during app start. To avoid this - EPiServer allows you to set this forceBinFolderScan flag to force bin/ folder (and probing folder for v7) scanning for assemblies. If flag is set to true - EPiServer is not asking AppDomain for loaded assemblies - but instead scans the filesystem and loads dlls that are not yet loaded.
Decompiled EPiServer source code and found that when forceBinFolderScan attribute is set to true makes EPiServer framework to scan each dll in bin folder. It iterates through all dlls and loads them into AppDomain.
If this attribute is set to false, it doesn't scan bin folder, but relies on ASP.NET assembly loading.
After assemblies are loaded in AppDomain from bin (or not loaded if attribute is false) it gets all assemblies from AppDomain and then filters them based on add/remove configuration. So add/remove tags do not affect bin folder scanning.
Actually this behavior and reason for such behavior is described in EPiServer documentation: MEF - The Discovery Mechanism (see note at the bottom of paragraph). Author just didn't mentioned that it is controlled by forceBinFolderScan attribute.
UPDATE
Here is an example which describes that behavior.
Assume that we have two assemblies: MyPlugins.dll - which contains some plugins and NoPlugins.dll. Also assume that those DLLs are not loaded by ASP.NET at application start.
We have this configuration which tells not to force scan bin folder and include all assemblies except NoPlugins.dll:
<scanAssembly forceBinFolderScan="false">
<add assembly="*" />
<remove assembly="NoPlugins.dll" />
</scanAssembly>
With such configuration MyPlugins.dll and NoPlugins.dll is not loaded in AppDomain and can't be scanned. So no plugins will be available.
If we set forceBinFolderScan="true":
<scanAssembly forceBinFolderScan="true">
<add assembly="*" />
<remove assembly="NoPlugins.dll" />
</scanAssembly>
With such configuration both DLLs are explicitly loaded from bin folder into AppDomain. Then filtering occurs and NoPlugins.dll is removed from module/plugin scanning collection. As a result plugins from MyPlugins.dll will be loaded.
UPDATE 2
Tested different configurations to see if optimizations help, but seems that filtering assemblies gives even worse results.
My site has quite a lot of assemblies, so it takes a lot of time to start up. I tried 3 different scenarios.
1:
<scanAssembly forceBinFolderScan="false">
<add assembly="*" />
<!-- Remove assemblies generated by EPiOptimizer -->
<remove assembly="..." />
</scanAssembly>
2:
<scanAssembly forceBinFolderScan="false">
<add assembly="*" />
</scanAssembly>
3:
<scanAssembly forceBinFolderScan="true">
<add assembly="*" />
</scanAssembly>
I performed simple tests 3 times each - did iisreset and in Chrome refreshed page and checked timeline (I know it is not perfect test) and here are results:
1: 1.3 min, 1 min, 1.3 min
2: 1 min, 57 s, 1 min
3: 57 s, 57 s, 57 s
I tried these tests else several times in different order, but results were same. So it is not reasonable to make optimizations by adding tag. Seems that it is more expensive to filter out assemblies which are loaded in AppDomain then to scan all of them. The strange thing is that forcing bin folder scan gives better results, but probably it is my test issue.
With that flag set to true, EPiServer will scan the bin folder during the site startup for assemblies that have EPiServer plugins. This detection is done by loading the assemblies and checking if they have classes that have the EPiServer plugin attribute or are EPiServer initialization modules.
You can use this tool to check which assemblies can be removed from that section, in order tom improve startup time.
http://www.david-tec.com/2011/11/Optimising-EPiServer-start-up-times-during-build-with-EPiOptimiser/
With forceBinFolderScan set to true, the EPiServer initialization engine will scan through all assemblies in the bin folder. If the assembly contains a reference to MEF (System.ComponentModel.Composition.dll), then that is scanned for classes marked with the IInitializableModule attribute. Any classes found then have its Initialize method called.
If you set forceBinFolderScan to false, then no assemblies are scanned, and you have to explicitly add any assemblies containing plugins by adding an entry in the scanAssembly element. E.g
<scanAssembly forceBinFolderScan="false">
<add assembly="AssemblyWithPlugins.dll" />
</scanAssembly>
Or the opposite, you can exclude assemblies known not to contain plugins, or those you don't wish to be scanned, and initialized by the initialization engine:
<scanAssembly forceBinFolderScan="true">
<remove assembly="AssemblyWithOutPlugins.dll" />
</scanAssembly>
Only scanning specific assemblies can improve site startup time, but you have to remember to update the list with any new assemblies added, or any plugins in those assemblies won't be loaded by EPiServer.
You can see this activity in the Log4Net log, by setting the log level to Warn or higher, you'll see messages such as "Not scanning {0} since it lacks any refererences to MEF" etc.
There is a great blog post about leveraging this feature to improve site startup time
Related
I need to update dlls from site in my WPF project. As for .exe or msi file updating is everything clear. But what about dlls? I do not know what to start with or how it should look like... I implemented exe updating through xml file - read xml file from server and if version is higher - load this new version. As for dlls - there are a lot of them, they can be of new versions or new dlls at all... So, I have a question at all - HOW TO IMPLEMENT CHECK? (examples appreciated or just theory answers). And many small questions like If I need to read xml file - how to generate it automatically (to write all dllls not good idea). Waiting for your advice.
First, consider ClickOnce deployment.
If ClickOnce is not a good choice for you (it has its limitations compared to installers). You can implement you own self-updating mechanism.
Normally this is done by a standalone update util (let's call it update.exe), which checks your update website on a scheduled basis.
When you need to deploy a new version of your application (with updated exes, dlls and data files), you can define an XML that list the latest version information of all the files,
<files>
<file name="foo1.exe" version="2.3.0.2" hash="23ac4544490cb3bac23ac4544490cb3bac" downloadurl="youwebsite.com/dl/v23/foo1.exe"/>
<file name="subdir/foo2.exe" version="5.2.1.1" hash="..." downloadurl="..." />
<file name="bar.dll" version="1.3.0.2" hash="..." downloadurl="..." />
<file name="subdir/bar2.dll" version="1.3.0.3" hash="..." downloadurl="..." />
</files>
When update.exe is launched, it downloads and parses this xml to determine which files need to be updated, and download these files from the download url, validate the integrity of the files with the hash value, and stop the application to replace the original files, and then restart the application.
To answer your question as how to generate this huge xml:
Of course not edited by hand. Write a util that iterates through all the files in the install dir (the latest version), for each file, get the file version (use System.Version class), the file size (use System.IO.FileInfo class), generates a hash value from the content of the file (use something like System.Security.Cryptography.SHA256), and form the hugh xml (use XDocument/XmlDocument class).
I have a situation where I need to add localised satallite assemblies to an existing XAP file. This is in the context of a SharePoint webpart.
The problem is that when I add the de/Assembly.resources.dll and rebuild the XAP, it fails to load in the browser. The mode of failure depends on how I attempt add the assembly to the AppManifest.xaml. In some cases, it just shows nothing in the browser. In others, it shows the loading spinner stuck at 0%.
My procedure is as follows:
Extract XAP
Extract the .resource from core webpart assembly
Convert to .resx
Translate
Rebuild as delay signed satallite assembly
copy to 'de' subfolder
Add to AppManifest
Rebuild XAP
Copy back to 14 hive
IISRESET
Clear browser cache
Test
The original assemblies are signed and so I have disabled assembly verification checking sn -Vr [star],[star] and have modified the registry to include 64bit and 32bit entries for verification checking. Assembly verification check skipping has been proven on the same system in a non-Silverlight/XAP context. The assemblies are built with the same .net version. SharePoint timer service was restarted after sn -Vr to reload exception list for verification skipping.
I must be missing something, but I don't know what.
In one Silverlight localisation guide I saw that the .csproj contains a string of supported localisations - I doubt the original base assembly was build with any other cultures specified - could this be the problem?
I need to make 3rd party (I'm a software distributor) extensions to some OOTB components of the software I resell. I have permission for this, and can even get my assemblies signed when the time is right, but I have no source access and any changes to the core component take a long time and a lot of effort - i.e. undesireable.
Assistance greatly appreciated. I have this working already for some ASP.net apps and standard webparts - but this Silverlight based web-part remains a problem.
Many thanks.
How do we overwrite config file at runtime. I have four config files for DEV, TEST, UAT, PROD. Based on user selection I need to overwrite the default config file completely with one of the selection specific config files. These config files not only have appsettings section, but also has complex cutom sections and subelements with lot of attributes. I need to overwrite and refreshsections dynamically at runtime. I know there are so many articles on editing appsettings sections. But I want to completely overwrite the entire file. Your help in VB.net is appreciated.
I have custom sections :
Using ClickOnce, I do not believe you can or should change files within the installation folder because it is read-only... Therefore, you have a choice: go with an MSI install and a custom install action to switch in the appropriate config file or build up some custom configuration elements to encapsulate your different environments.
In our application, we have done the latter. We have something like the following custom configuration section in our main app.config.
<myApp defaultEnvironmentName="prod">
<environments>
<add name="prod" title="Production" description="Full production environment" injectionContainers="prod">
...
<!-- Add custom elements the affect your environment -->
...
</add>
<add name="qa" title="Quality Assurance" description="Full production environment except running off our mock database" injectionContainers="prod qa">
...
<!-- Add custom elements the affect your environment -->
...
</add>
</environments>
</myApp>
... <!-- Other elements that are common to all environments --> ...
Then we use a run-time flag or command line argument to enable you to switch between environments easily. The value of the environment in use is stored in a user Settings file so that on subsequent use the application will load the last used environment.
When we need to access something that varies per environment we directly call upon the custom configuration section's CurrentEnvironment property which utilised the above mentioned setting to work it out:
var title = MyAppSection.Configured.CurrentEnvironment.Title;
Note that here, MyAppSection.Configured is just a singleton instance that loads based on ConfigurationManager.GetSection(...).
I realise the prospect of a boat-load of configuration code is the last thing you want but it will let you clearly define and isolate your environment variables within the config files.
I have a common silverlight project. This project project, among other things, includes constants and static classes.
The silverlight App i have references this common library.
In addition, i have a handful of external modules that are loaded on-demand (via Prism). Each module is its own .Xap file and they too reference the common library.
So now each Xap in my silverlight application has a reference to the Common.dll.
Does this mean the common.dll is loaded every time a xap is loaded, or does it essentially mean only the main App's common.dll is ever loaded?
The ultimate question im getting at is this:
If i make a code change (bug fix) in the common.dll, do i have to release ALL Xap files or just the main App xap?
Thanks.
If you use Assembly Caching in all projects that reference the common dll then you'll just get one copy downloaded as it's own zip file. This way all the different XAP files will reference the same dll. Otherwise common.dll will be included in each XAP file that references.
You'll need to create a common.extmap.xml file for your common.dll which needs to be in the same folder from where the dll is referenced.
By default DLLs are loaded on demand. This means that you can't really guarantee which directory they will load from. This is a common issue among modular applications and one that there isn't a ready prescription for. It depends on requirements, essentially.
Some things you can do:
GAC the Common.dll in the target environment. This will allow you to control the versioning of that DLL centrally.
Release everything every time Common.dll changes (as you mentioned).
We have opted for number 2 (we treat our "Common.dll" as a contract assembly that changes rarely) in order to keep our xcopy deployments intact.
Number 1 might make more sense if you anticipate that code churn on Common.dll will be high or you want to keep your deployment schedules for modules completely autonomous (like if the modules were being developed and deployed by seperate teams with seperate build and source respositories, for example).
Edit: It looks like Silverlight has something to provide an xcopy variant of the GAC approach. ChrisF's answer is probably the way I would go with Silverlight (we do WPF, so that's a bit different). I'll leave this here for posterity.
I'm using MEF in silverlight to dynamically load some plugins from a secondary xap file. This secondary XAP file is built from a project that references various plugin projects, all of which are built against dlls that are already in the primary xap file.
As such, I want pretty explicit control over which dlls end up in this secondary xap. Including any dlls from the main xap file is redundant (and also causes issues with MEF recomposition). But Visual Studio seems to insist on including various dependent dlls even when the CopyLocal property is only set to True for the references to the plugin projects.
So far the only thing I've found that works is to add explicit references to probelmatic always-included dlls in the top-level project that builds the secondary xap, and set CopyLocal to False in the reference properties. But this is brittle as the dependencies change.
Am I thinking about this wrong? Should I just be building a separate xap for each plugin dll (in which case setting CopyLocal to false for all references seems to work)?
As well as setting Application Library Caching on your Silverlight project by selecting the "Reduce XAP size by using application library caching" option in your project settings (source) you need to have an extmap.xml file in the same location as your shared dll.
So if your dll was Microsoft.Expression.Effects.dll then you'd need to create (or copy) Microsoft.Expression.Effects.extmap.xml.
It looks like this:
<?xml version="1.0"?>
<manifest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<assembly>
<name>Microsoft.Expression.Effects</name>
<version>2.0.20525.0</version>
<publickeytoken>31bf3856ad364e35</publickeytoken>
<relpath>Microsoft.Expression.Effects.dll</relpath>
<extension downloadUri="Microsoft.Expression.Effects.zip" />
</assembly>
</manifest>
The version number should match the version number of the dll.
If you don't have the public key token you can replace that with null.
This will copy the dll to a separate zip file which can be then shared by several xap files or only downloaded once if it's not going to change when you xap file changes.
Take a look here: http://msdn.microsoft.com/en-us/library/dd833069(VS.95).aspx
Specifically, look at the section entitled "To configure an assembly for use with application library caching". It describes a method for doing something that's at least pretty close to what you're looking for.