Zobrazují se příspěvky se štítkemASP.NET. Zobrazit všechny příspěvky
Zobrazují se příspěvky se štítkemASP.NET. Zobrazit všechny příspěvky

sobota 21. dubna 2012

Common.Logging and compatibility with other libraries

It has been the second time since I have run into the issue of configuring correctly Common.Logging on my project. So what is the problem? Let's start with the basics:

Common.Logging should be a generic interface for logging which can be used by other frameworks and libraries to perform logging. The final user (you or me) uses several frameworks in his final application and if all of these frameworks will use different logging framework it will turn into configuration nightmare.So our favorite frameworks such as Spring.NET, Quartz.NET are using Common.Logging. This interface in turn uses a concrete logging framework to perform the logging (the act of writing the log lines to somewhere).

Typical scenario can be for instance Common.Logging and Log4Net combination. In our application configuration file (web.config or app.config) we have to configure Common.Logging to use the Log4Net and than we can continue with the Log4Net configuration specifying what should be logged.

<common>
<logging>
 <factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4Net">
 <arg key="configType" value="INLINE" />
 </factoryAdapter>
</logging>
</common>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
 <layout type="log4net.Layout.PatternLayout">
 <conversionPattern value="%date %-5level %logger - %message%newline"/>
 </layout>
</appender>
</log4net>

My general problem is that Common.Loggin.Log4Net facade is looking for a concrete version of the Log4Net library. Concretely the version: 'log4net (= 1.2.10)'. That is not a problem if you are not using some other framework which depends on higher version of Log4Net.
In my case the le_log4net library (the logentries library) is using log4net 2.0. So if you are using NuGet, you might obtain the following exception while adding the references:


image


The similar thing might happen if you just decide to use the latest Log4Net by default. Then you might get an exception when initializing Spring.NET context or starting the Quartz.NET scheduler:


Could not load file or assembly 'log4net, Version=1.2.0.30714, Culture=neutral, PublicKeyToken=b32731d11ce58905' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)


Solution 1: Ignore NuGet, define Runtime Binding


One way to get around this is to define runtime assembly binding. But this solution forces you to add the reference to log4net manually. NuGet controls the version and wont let you at references on the fly the way that you would. So to get over add the latest Common.logging.Log4net façade and Log4Net version 2 (which you need for some reason). Than you have to define the assembly binding in the configuration file.

<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
 <dependentAssembly>
 <assemblyIdentity name="Common.Logging" publicKeyToken="af08829b84f0328e"/>
 <bindingRedirect oldVersion="1.2.0.0" newVersion="2.0.0.0"/>
 </dependentAssembly>
</assemblyBinding>
</runtime>

Solution 2: Just use the older version of Log4Net (1.2.10)


If you do not have libraries that are dependent on Log4Net version 2.0.0 than just remember to always use log4net 1.2.10. This is the version which Common.Logging.Log4Net is looking for. Or just let NuGet manage it for you. You can add Common.Logging.Log4Net via NuGet and it will automatically load the correct version of Log4Net.


Solution 3: Try other logging library for instance NLog


This actually is not a real solution. I have experienced similar issues while using NLog, concretely try to use the latest NLog library with the Common.Logging.Nlog façade and you will obtain something similar to:


{"Could not load file or assembly 'NLog, Version=1.0.0.505, Culture=neutral, PublicKeyToken=5120e14c03d0593c' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)":"NLog, Version=1.0.0.505, Culture=neutral, PublicKeyToken=5120e14c03d0593c"}


The solution here is similar, you will have to define Runtime Binding:

<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
 <dependentAssembly>
 <assemblyIdentity name="NLog" publicKeyToken="5120e14c03d0593c" culture="neutral" />
 <bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
 </dependentAssembly>
</assemblyBinding>
</runtime>

What was interesting here, is that NuGet actually took care of this for me. I have just added the Common.Logging.NLog façade and I guess NuGet spotted that I have already NLog 2 and that this Runtime Binding is necessary. If you look at the documentation of bindingRedirect you will see, that we have the right to specify the range of versions in the oldVersion attribute. Here all the version will be bound to the 2.0.0.0 version.


Summary


Anyway NLog and Log4Net are both cool logging frameworks, just use the one you prefer. As I have showed above it is possible to use them together with Common.Logging it just takes a few more lines to configure it correctly.

neděle 7. února 2010

TargetInvocationException when using CreateTaskWithContentType activity

If you want to use ASP.NET pages with your workflow in SharePoint you need to follow these steps:

1) Create the web page.
2) Create ContentType containing your WebPage.
3) Add the ContentType to the ContentTypes gallery in SharePoint site.
4) Allow ContentTypes on the SharePoint task list, where the task of your workflow will be stored.
5) Add the ContentType to the list where your workflow tasks will be stored.
6) Finally you can use CreteTaskWithContentType activity and specify the GUID of the ContentType which you have created.

For more details of how to develop SharePoint workflows with ASP.NET pages refer to this blog.

If you do not add the ContentType to the gallery or if you forgot to add it to the SharePoint list, you can receive the following exception:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.NullReferenceException: Object reference not set to an instance of an object. at Microsoft.SharePoint.Workflow.SPWinOETaskService.CreateTaskWithContentTypeInternal(Guid taskId, SPWorkflowTaskProperties properties, Boolean useDefaultContentType, SPContentTypeId ctid, HybridDictionary specialPermissions) at Microsoft.SharePoint.Workflow.SPWinOETaskService.CreateTaskWithContentType(Guid taskId, SPWorkflowTaskProperties properties, String taskContentTypeId, HybridDictionary specialPermissions)


The best way to add the ContentType to the ContentTypes library is to create Feature containing all your ContentTypes and install and activate the feature on SharePoint. On details pleas follow the part 4 of the above mention blog how-to.

Programatically allow and add ContentTypes on SharePoint list


Here is a method which I am using to programatically alow and add ContentTypes on SharePoint task list, which accepts String representing the GUID of the ContentType and SPList representing the task list.

I've found the code in this method again in part 4 of this great series.


public static void AllowContentType(SPList lTaskList, String lTaskContentType)
{

//make shure that the content types are enabled on the task list
if (lTaskList.ContentTypesEnabled != true)
{
//if not allow them. This can be done also in the SharePoint GUI
lTaskList.ContentTypesEnabled = true;
}

// convert given String representing the GUID to SPContentTypeId
SPContentTypeId myContentTypeID = new SPContentTypeId(lTaskContentType);

// Find the content type in SharePoint site content types library
SPContentType myContentType = lTaskList.ParentWeb.Site.RootWeb.ContentTypes[myContentTypeID];

//if the content type was found
if (myContentType != null)
{

// Check if the content type was already added to the SharePoint task list
bool contenTypeExists = false;
foreach (SPContentType contentType in lTaskList.ContentTypes)
{
if (contentType.Name == myContentType.Name)
{
// This content type was already added
contenTypeExists = true;
break;
}
}

// If I didn't find this content type in the list I will have to add it
if (contenTypeExists != true)
{
lTaskList.ContentTypes.Add(myContentType);
}
}
else
{
throw new Exception("Content type is not register with the web site");
}
}
Přihlásit se k odběru: Komentáře (Atom)

AltStyle によって変換されたページ (->オリジナル) /