How do I stop Nhibernate log4net conflicting with existing log4net? - nhibernate

I'm very new to this so I apologise if my question isn't well structured or just in the wrong place, etc. I've had a good look for solutions to this and tried a number of different approaches but haven't found anything that works so....
I have a solution that makes use of Nhibernate, and consequently must use log4net V1.2.10.0, which comes in the log4net/2.0/ folder. However my solution also links to a number of other solutions, to which I have very limited access. These make use of the same log4net V.1.2.10.0 but in folder: log4net/1.2/
When I run my solution I get this error.
{"Could not load file or assembly 'log4net, Version=1.2.10.0, Culture=neutral,
PublicKeyToken=e27b8fa57f63a98d' or one of its dependencies. The located assembly's
manifest definition does not match the assembly reference. (Exception from HRESULT:
0x80131040)":"log4net, Version=1.2.10.0, Culture=neutral,
PublicKeyToken=e27b8fa57f63a98d"}
I have tried to amend the solutions that it is calling, however each time I amend one I get the error within that solution as soon as it tries to use another solution, so I have to amend another and so on. There are simply too many solutions to amend and too many interdepencies with other solutions that I have absolutely no control over for me to be able to change them all so that they use log4net/2.0.
I have found another question ( Referencing 2 different versions of log4net in the same solution ) which I think is basically the same problem, and they amend the app.config with a binding, however I can't seem to get this right, as I'm still getting the same error. The binding I've included in my app.config is this:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="log4net" publicKeyToken="e27b8fa57f63a98d" />
<codeBase version="1.2.10.0" href="2.0\log4net.dll" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="log4net" publicKeyToken="1b44e1d426115821"/>
<codeBase version="1.2.10.0" href="1.2\log4net.dll" />
</dependentAssembly>
</assemblyBinding>
</runtime>
I'm not sure what the answer to the other question means when it says "You create 2 folder in your project one for each version of log4net. You place each log4net.dll in its corresponding folder by adding an the file to the solution (not with add reference). You can set the copy to output directory property to copy always so that it is automatically copied to the output folder when you build." And would I need to do this to every solution that my solution references?
Ideally I want to be able to make an amendment to my solution which simply means that it doesn't care what log4net any of the solutions are using but they can still pass log messages between each other. I assume this is possible, so any help would be hugely appreciated. Either that or how do I turn off nHibernate's logger so that it doesn't care what log4net I'm using so I can just continue to use the log4net/1.2 that all the other solutions are using. I've tried all sorts of things to turn it off but it still seems to end up trying to find the log4net/2.0.

You're lucky in that you've got the same DLL in two different places, which makes your problem easier to solve. You could simply take a back up and then delete one of the references of the DLL (the \1.2\ version?) and then resolve any broken references in your solution - that should get you to a point that you can compile.
Have you tried NuGet too? You could add a reference to Log4Net and then add a reference to Nhibernate, which would see that you've already satisfied it's dependency requirement and would not need to download another reference to NHibernate.
I'd recommend the learning curve of using NuGet because it is a powerful tool that should make your life much easier in the long run.
Update
Please see my comment about providing your current folder structure to help - incase you can do that; the following should get you started.
To try and do this using just direct file references you may need to move your DLL's around into a better structure. Inside your solution (not project) create the following folder structure under solution items.
\ExternalReferences
\Log4Net\
\NHibernate\
Move a single copy of the log4net DLL inside the log 4 net folder (and delete the other instance) and then move all the NHibernate DLL's you are using (minus Log4Net) in the NHibernate directory. Remove the bindings inside your app.config and then go through each project updating the references to point to the version inside the external references.
The actual location of the files isn't that important, you just need your code to reference a single instance of the DLL and then when it builds they all get copied into the bind folder. You're just running into problems because you have two instances - whilst you are editing your code, etc. NHibernate isn't actually too bothered where Log4Net is; it just has a dependency on it that must be forfilled when it runs.
Update 2
New Version of Log4Net on NuGet that breaks backward compatibility - see the referenced blog post for more info. There is now a 1.2.11.0 version of Log4Net that contains a different strong name to 1.2.10.0, making things just that little harder!

Related

How do I add reference in vb.net without Visual Studio?

I have found some free compilers online, but I can't figure out how to add external references to any of them. Is there a special Imports statement I can use, so that VB.NET will go looking for a third party .dll in a certain relative path, so that I don't have to add references through Visual Studio? The specific reference I am trying to add first is the DI interop for SAP B1, but this probably isn't going to be the only one I will need to add.
I know that I can add a /reference to add a reference in a command line compilation, if I am using Microsoft's command line compiler, but that seems to be against the license for my client now. I gather the old Express 2010 versions could compile and add references without revenue restrictions, but I am looking for syntax on how to tell a compiler to add a reference, not a software recommendation (since I don't think I can still get those Express editions).
The answer is as #Jaxedin and #T.S. said in comments to the question, but I wasn't aware of the existence of the MSBuild software.
I had read in various places in reference to MSBuild comments like "And keep in mind that for now, you’ll need to have Visual Studio 2015 installed in order to build the first time." (MSDN), and just took them for face value.
Being able to put the references inside an XML .vbproj is much easier than I had been imagining. Something like:
<ItemGroup>
<Reference Include="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<Name>System</Name>
<SpecificVersion>True</SpecificVersion>
<HintPath>...\systemDir\System.dll</HintPath>
<ReferenceOutputAssembly>True</ReferenceOutputAssembly>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Reference>
</ItemGroup>

LINQPad DbProviderFactories GetFactoryClasses

I have found that adding an entry to the DbProviderFactories in LINQPad.exe.config does not make it show up in System.Data.Common.DbProviderFactories.GetFactoryClasses().Dump();
I had to add it to machine.config to be able to see it and use it. Is that to be expected?
Specifically I was trying to add the Oracle ODP managed entry since an assembly I reference requires it. I am told that the point of using the managed provider was to make the assembly more self contained and portable and so having to touch machine.config trashes that idea.
Try adding it to Linqpad.config. The Linqpad.exe.config file is for LINQPad itself whereas linqpad.config is for your queries.

MVC - Application Assembly

Question:
If I have multiple projects in one solution is it still considered a single assembly?
Background Information:
I'm aware the 'MyApplication/Properties/AssemblyInfo.cs' file exists. Further, I confirmed that when I:
Add a project to the solution.
Appropriately reference the newly added project.
Lastly, Build the solution.
The 'MyApplication/Properties/AssemblyInfo.cs' file has not changed. This leaves me to believe, and please correct me if I'm wrong that I'll have met the demand.
Thank you
No.
Each project is compiled into one assembly in your case. The assemblyinfo.cs file (for each project) should not change at all when you compile anything. Also, that file's name is not important at all; it's the global attributes inside it that cause various properties of the assembly being created to be set. That file's name and location are simply a convention.

Setting MSBuild 'Condition' attribute via Visual Studio extension

I have a C# project which is built in a few different configurations. Some of the source files should be always included, and some only in certain configurations. So far I've been doing this with #if ... #endif around the entire files, but I was hoping to create a small extension to do this a nicer way.
I've created an extension that adds an item to files' context menus, but I can't find any way to set the Condition attribute on the item node in the project file.
I've looked at the Properties collection of the EnvDTE.ProjectItem interface, but can't see anything useful there (except BuildAction... I'll come back to that).
Then I tried getting an IVsBuildPropertyStorage on the item and calling SetItemAttribute(). This does add information to the project file, but as a child element like this:
<ItemGroup>
<Compile Include="Program.cs">
<Condition>%27%24%28Configuration%29%27==%27Debug%27</Condition>
</Compile>
</ItemGroup>
when what I was trying to achieve was:
<ItemGroup>
<Compile Include="Program.cs" Condition="'$(Configuration)'=='Debug'" />
</ItemGroup>
There's also an IVsBuildPropertyStorage.SetPropertyValue() but that adds a similar child element to a PropertyGroup section near the top, not to the item node.
I've looked at 'Project Subtypes/Flavors', but that looks like it's just going to get me another IVsBuildPropertyStorage, which doesn't seem to be useful. They do look capable of a lot of complex things, but documentation on the subject appears to be minimal and vague.
I've seen some posts describing how to use the MSBuild assemblies to directly load and manipulate the project file, but I'm not sure when is safe to do that without confusing Visual Studio and potentially losing changes, since VS prompts to reload when it detects changes to the project file.
As a last idea, I thought about manipulating the BuildAction property between Compile and None, but that sounds like it could be a lot of work for my extension to maintain correctly, keeping it in sync with every time the user switches configurations in the IDE for example.
Is there anyone with any experience with this kind of thing that has any advice to offer me, or should I give up hope and stick with manually adding #if directives everywhere?
You may like to explore the MSBuild option you mentioned.
You don't actually have to load the MSBuild project from file, because Visual Studio gives you a way of accessing the MSBuild project directly, i.e.:
string projectPath = projectItem.ContainingProject.FullName;
MsBuildProject project = ProjectCollection.GlobalProjectCollection.GetLoadedProjects(projectPath);
var compileItems = project.GetItems("Compile");
From there you can locate your specific items and potentially add the condition attribute, though I haven't tried this step myself (if this doesn't work, you might have to try modifying the project elements under the project.Xml property instead).
You can then call project.Save(), which shouldn't trigger the "Reload project?" dialog because of the way the MsBuild project instance is linked to the Visual Studio project hierarchy.
However, you may like to force Visual Studio to reload the project anyway, because if you switch build configurations (e.g. between Debug and Release), the MSBuild engine may not re-evaluate your item conditions during build. The code to do this programmatically can be found here:
How do I programmatically refresh/reload a VS project after modifying the underlying file?
Unfortunately I never got the time to persue the original goal of creating an extension for doing this, however I did achieve what I needed using the suggestion by lex-li: using separate project files per configuration.
Since the project files can all reside in the same directory, it's easy to simply use the 'Include/Exclude from project' context menu item in the solution explorer to choose which files are included. There's also no need for file linking this way, which I'd tried before and found very time-consuming to manage.
Partial Methods are also worth looking at, if you have similar needs. They allow you to define the signature of a method in one place, but optionally implement it elsewhere. If you don't implement it, no call is generated by the compiler.
With respect to the original idea of the extension, I suspect the answer by Daniel Nolan was heading in the right direction, but unfortunately I didn't get to try it out.

Is AssemblyInfo.cpp necessary?

I want to remove AssemblyInfo.cpp, because of some metadata errors that sometimes come up.
Is AssemblyInfo.cpp useful for anything? Or can it be removed without any problem?
I've discovered one distinction for this file: it has to do with values reported under calls to Assembly.GetReferencedAssemblies. I was working on tracking version numbers of our binaries from our SVN repository by embedding the revision numbers into them. Initially I too was updating AssemblyInfo.cpp and found nothing reported in the file property details tab for the binary. It seemed this file did nothing for me in terms of updating those details, which was not the case with similar updates to a csproj's AssemblyInfo.cs. Why the difference right?
Now in one such csproj we happen to reference a vcxproj and that csproj dumps to a log the versions of all its referenced assemblies using the .NET Assembly.GetReferencedAssemblies method. What I discovered was that the number that was being reported in that log was not the vcxproj's version as given by the VS_VERSIONINFO resource I added (which does get the version details into the file properties details tab). Instead the number reported was actually matching that defined in the AssemblyInfo.cpp.
So for vcxproj files it looks like VS_VERSIONINFO is capable of updating the contents you find under the file properties details tab but AssemblyInfo.cpp is capable of exposing the version to GetReferencedAssemblies. In C# these two areas of reporting seem to be unified. Maybe there's a way to direct AssemblyInfo.cpp to propagate into the file details in some fashion, but what I'm going to wind up doing is duplicating the build info to both locations in a prebuild step. Maybe someone can find a better approach.
So far I never had the AssemblyInfo.cpp in my managed c++ dlls, so I don't think it is necessary.
(I just added the file to have version information for my c++ dlls).
Why not just fix the errors? On that note, what errors are you getting?
This file provides information such as a version number which is definitely needed in order to use the assembly you have built.