NService bus and the GAC - c#

I have recently tried to migrate the NServiceBus libraries to the GAC as they are pretty big and are required in nearly all of my software. I am using the newest .NET 4.0 Build (2.0.0.1219) and have used GACUTIL to copy NServiceBus & NServiceBus.Core into the new GAC and log4net into the old 2.0 GAC. I have managed to get log4net working by wiring in the version and PublicKeyToken but I cannot get the NServiceBus.Core working. Every time I start a piece of software I get the following error:
"Type NServiceBus.Unicast.Transport.CompletionMessage was not registered in the serializer. Check that it appears in the list of configured assemblies/types to scan."
When I copy the DLL NServiceBus.Core to the local folder it works fine.
my config looks like this:
<configSections>
<section name="MsmqTransportConfig" type="NServiceBus.Config.MsmqTransportConfig, NServiceBus.Core, Version=2.0.0.1219, Culture=neutral, PublicKeyToken=9fc386479f8a226c" />
<section name="UnicastBusConfig" type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core, Version=2.0.0.1219, Culture=neutral, PublicKeyToken=9fc386479f8a226c" />
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821" />
<sectionGroup name="common">
<section name="logging" type="Common.Logging.ConfigurationSectionHandler, NServiceBus.Core, Version=2.0.0.1219, Culture=neutral, PublicKeyToken=9fc386479f8a226c"/>
</sectionGroup>
So i'm wondering has anyone else got NServiceBus successfully working with the GAC?
Cheers

It is an issue with NServiceBus stripping strong names. Use the <runtime> element in web.config:
<runtime>
<qualifyAssembly partialName="MessagesDll" fullName="MessagesDll, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4d476a51357cea5c" />

NServiceBus scans the assemblies in a directory (the run directory for an application, the website's compiled directory for a web application) in order to load all the message handlers, and that means it needs to scan itself as well for all the types it needs for dependency injection.
I'm not sure that this model supports assemblies living in the GAC by default, although if you're configuring NServiceBus yourself, you can specify the assemblies to load yourself through the NServiceBus.Configure.With(params Assembly[] assemblies) overload, just make sure to include all the NServiceBus assemblies and Log4Net at the very least.
However, I would contend that GAC-ing the NSB assemblies might not be the best idea. Each endpoint having its own copy of the assembly reinforces the autonomy of the endpoints, and will make it much easier if you ever need to upgrade to a new version of NServiceBus, since you would be able to test each endpoint individually and not just put a new assembly in the GAC, add a binding redirect, and hope everything continues to run fine.

Related

Mock Umbraco configuration in test project

When running unit tests on code using some Umbraco Core extensions, such as string.ToUrlSegement(), the following error is thrown:
System.Configuration.ConfigurationErrorsException: Could not load the Umbraco.Core.Configuration.UmbracoSettings.IUmbracoSettingsSection from config file, ensure the web.config and umbracoSettings.config files are formatted correctly
How do you prevent this happening?
Beside copying all Umbraco settings into your test projects app.config, you can add the following configuration:
<configSections>
<sectionGroup name="umbracoConfiguration">
<section name="settings" type="Umbraco.Core.Configuration.UmbracoSettings.UmbracoSettingsSection, Umbraco.Core" requirePermission="false" />
</sectionGroup>
</configSections>
This prevents that exception being thrown when using Umbraco core functions dependent on configuration of a main project.
Discovered this and some other great tips here.

Change Build Output Directory of WebApi Application

I am part of a team working on a large application. I am a new addition to this team and am building a new piece of the app. As part of this process, I've created a WebApi application that will expose some HTTP endpoints through which I will retrieve information about the app.
Due to conditions it would take far too long to explain, I'd like to get the WebApi project to build in another directory, specifically ..\bin\Server\Debug\ as this is where most of the other portions of the app build to. I would not bother except that the app tried to use files that are found based on the working directory which is currently wrong for my WebApi app.
I tried changing it in the project settings and now I get this error:
My Googling has turned up little help thus far. Anyone know how to resolve this?
Try adding a runtime probing path in the configuration:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="bin\server\Debug;"/>
</assemblyBinding>
</runtime>
</configuration>
In addition to above step and to get rid of globa.asax error. Open the mark up of Global.asax file and Add follow line on the top.
<%# Assembly Name="<you_web_app_assembly_name_here>" %>
Now you'll start getting the error of System.web or BindingProvider not found etc. There's weird fix for it start adding assemblies to assembly tag under compilation.
<compilation debug="true" targetFramework="4.5" optimizeCompilations="false">
<assemblies>
<add assembly="Microsoft.AspNet.Identity.Core, Version=2.2.1, PublicKeyToken=31bf3856ad364e35" />
<add assembly="System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Optimization, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</assemblies>
</compilation>
You'll get few more errors like this but this will get you going.
Reason: The problem I see is that there's an option to change the output path but Asp.net does on the fly compilation. Which why the error are compilation related when you try to run the website. Somewhere the run time compilation only look in \bin folder and which is why we have to specify every assembly that the project is referencing to.
Update -
Unfortunately you can not change the bin directory. After looking at all options and digging found that bin folder of Asp.net web project is not ordinary binary output folder. It's a share code folder from where the binaries are referenced directly in the project.
The binaries are compiled when a first request is received by webserver for Asp.net application. And bin folder is only use as shared binary references folder and not the actual output folder/directory.
The actual output folder of On-the-fly compilation in Asp.net is default set to %SystemRoot%\Microsoft.NET\Framework\<versionNumber>\Temporary ASP.NET Files that you can change ofcourse from compilation tag attribute [tempDirectory][3] in your web.config.
After all these research I came to this conclusion that the option for changing the directory from project -> properties -> Build -> Bin is appearing because of Asp.net website project template. This gives the user same look'n feel as any other project. But the functionality of asp.net website remains the same. The Bin folder still works as it used to work in old website template of Asp.net.
You cannot change the output directory of an asp.net application due to IIS security restrictions, this is why it is not working.
If you are trying to manage dlls due to DI, copy all other satellite dlls into bin folder of your main asp.net app
You can try copying the dll with the after build target. First change the output path back to what it was if you changed it before. Then add some code like this in your project file.
<target name="AfterBuild">
<copy destinationfolder="..\bin\Server\Debug\" overwritereadonlyfiles="true" sourcefiles="$(OutputPath)\$(AssemblyName).dll" />
<copy destinationfolder="..\bin\Server\Debug\" overwritereadonlyfiles="true" sourcefiles="$(OutputPath)\$(AssemblyName).pdb" />
<copy destinationfolder="..\bin\Server\Debug\" overwritereadonlyfiles="true" sourcefiles="$(OutputPath)\$(AssemblyName).xml" />
</target>
This will put the built dll in to the folder specified in destinationfolder. I usually use this for class libraries but i don't see why it would not work for a web api project
You can check out my blog post on this if you like.
http://torontoprogrammers.blogspot.com/2014/11/msbuild-targets-and-tasks.html

Console App with Log4Net compiles in Debug but not in Release mode

I have a simple C#/4.0 console app that reference Log4Net 1.2.13.0 in VS2010.
In debug mode the app compiles and runs fine on my machine. However, as soon as I change to 'Release' I get the error
"Could not load file or assembly 'file:///C:\Users\mike\Documents\Visual Studio 2010\Projects\xxxx\yyyyy\log4net.dll' or one of its dependencies. Operation is not supported."
In the AssemblyInfo.cs I have added the line:
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
According to the configuration mgr, but Debug and Release are set to use platform x86. This is also happening in another C# service application on my laptop, but I thought it easier if stick with getting it working here first.
The app.config file contains a section for:
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
Thanks in advance
Mike
Changing the type definition in the app.config to specify the fully qualified assembly name resolved the issue for me:
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net, Version=1.2.13.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a" />
I too had the same issue. I just checked the Unblock checkbox at the properties of log4net.dll which resolved the issue for me.

How to change configSections, section, type element? Specifically Version

I'm posting my question here and to CodeProject, as a question to the famous article series on the mysteries of config files.
From the article:
Optionally, you may specify culture, version and public key (for
signed assemblies) values if you wish to ensure only a specific
version of an assembly is searched for when your .config file is
parsed.
I'm using the following code to open and initialize the config file:
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = path;
config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
section = (OptionsSection)config.GetSection("myoptionsdata");
if (section == null)
{
section = new OptionsSection(0, "aaaa", "bbbb", "cccc",14);
config.Sections.Add("myoptionsdata", section);
config.Save(ConfigurationSaveMode.Full);
}
That creates the following:
<configSections>
<section name="myoptionsdata" type="my.namespace.OptionsSection, myAssembly,
Version=1.0.3.0, Culture=neutral, PublicKeyToken=111222aaaabbb"
allowLocation="true" allowDefinition="Everywhere"
allowExeDefinition="MachineToApplication" overrideModeDefault="Allow"
restartOnExternalChanges="true" requirePermission="true" />
</configSections>
Notice how the 'type' has Version, Culture, and the PublicKeyToken. I need to eliminate these, or at least the Version. The problem is that I deploy the app with a specific version, then I bump the version and issue updates. But when the read is done on the config it fails because the version is explicit.
So really all I want is this:
<configSections>
<section name="myoptionsdata" type="my.namespace.OptionsSection, myAssembly" />
</configSections>
I have never once seen an example that includes the extended type values. Every example shows Save() creating type="namespace.class,assembly", and yet that doesn't seem to be the default behavior.
So, with reference to the above quote, where can I find information on managing those "optional" values?
For anyone googling, this is one of the causes of the infamous error below:
Exception: An error occurred creating the configuration section
handler for myoptionsdata: Could not load file or assembly
'myAssembly, Version=1.0.3.0, Culture=neutral,
PublicKeyToken=111222aaaabbb' or one of its dependencies. The located
assembly's manifest definition does not match the assembly reference.
(Exception from HRESULT: 0x80131040)
(C:\Users\me\AppData\Roaming\product\dir\name.config line 4)
I believe my question is similar to this one which so far has not received any response.
Going "off the menu", I just want to deploy a config file to a specific location (non-default) and allow users to set options in a Tools>Options sort of form. Most apps do this. Is there any easy and commonly accepted way of doing this? I should note that my app is an Outlook Addin, and I do my config file like this because I want to store addin settings in an addin-specific config file rather than anywhere near Outlook configs.
The assembly that contains your custom configuration section has a strong name. Strong-naming an assembly explicitly prevents the kind of in-place version upgrade you want to do. Remove the strong name from that assembly and the assembly loader will stop caring what version it is.

How do I reference configuration information from within multiple class libraries?

I've got a bunch of DLL projects that I'm pulling into my application, each contains their own Settings.settings/app.config. When I compile the app and run for debugging, everything works just fine, but come deployment time I can't get my DLLs to read their own settings files.
I've been doing some reading and it has become apparent that there's a couple of methods to getting each dll to read its own configuration - one is to dedicate a .dll.config to the library and the other is to embed the dll's configuration in the process.exe.config.
I'm having significant issues trying to implement either and I wondered if anyone has any good docs on this - there appears to be a shortage on the Net.
I'd like a separate .dll.config for each of the libraries if possible, but in a pinch, getting each of my libraries to read their own section of the process.exe.config will do.
Can anyone point me in the right direction because I'm so close to rolling this application out but this stumbling block is causing me a significant headache.
Edit: When I merge the configuration files, I start getting TypeInitializer exceptions when I initialize objects withing my libraries. This is likely just me being retarded, but does someone have a working example of a merged config file and some basic demonstrative code for reading it from multiple assemblies?
What are the "significant issues" you encountered? I started with embedding the dll's config in the exe's config, which worked, but was cumbersome. I now have all the config stuff in one dll project. The only thing I needed to do to make that work (besides copying the settings over) was to change the Settings class to be public.
Here's an example of a merged app.config that works:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="SharedConfig.Client.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<!-- Begin copy from library app.config -->
<section name="SharedConfig.Library.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<!-- End copy from library app.config -->
</sectionGroup>
</configSections>
<applicationSettings>
<SharedConfig.Client.Properties.Settings>
<setting name="Bar" serializeAs="String">
<value>BarFromClient</value>
</setting>
</SharedConfig.Client.Properties.Settings>
<!-- Begin copy from library app.config -->
<SharedConfig.Library.Properties.Settings>
<setting name="Bar" serializeAs="String">
<value>BarFromLibrary</value>
</setting>
</SharedConfig.Library.Properties.Settings>
<!-- End copy from library app.config -->
</applicationSettings>
</configuration>
Have each class library define configuration settings in a custom ConfigurationSection.
Then add custom section handlers to your process.exe.config file.
This MSDN article is pretty comprehensive in its explanation, with examples in both VB and C#.
See If app.config for a DLL should be in the "main config"… what do we do with WCF References in DLLs?. The real answer is "copy and paste". That's unfortunately the general solution Microsoft had in mind. In some cases, the .NET 2.0 Settings mechanism can be used, as it bakes the default values into the DLL itself. At runtime, the DLL can then save updated settings - into the .exe.config.

Categories