2013年12月24日 星期二

Common.Logging

在開始使用log4net或NLog這種Logging元件來處理log,是一個很美好的開發經驗,但在開發類別庫專案的時後,會碰到循環參考的問題,這時後改用Common.Logging會比較好

Common.Logging是一個Log介面,可以支援log4net、NLog、Enterprise Library Logging,透過設定檔把Log轉接到真正要使用的Log元件,在日後轉換Log元件的時後很方便,詳細的介紹可以參考官網,以下用一個類別庫專案搭配一個應用程式來介紹這個元件的使用方式

Common.Logging 2.2.0版之後,相依於Common.Logging.Core套件
應該是為了可儶性,把介面和抽象類別分離到Core套件
在套件的使用上要做點調整

Common Logging 2.3.1版之後,已不再使用Common.Logging.Core
為了比較好在Log套件的多個版本之間切換,對應的Log套件後面都會有指定的版本
例如Common.Logging.NLog31對應到NLog 3.1版本

首先開啟一個類別庫專案,並透過NuGet加入Common.Logging參考


簡單寫一個函式讓之後引用的程式來呼叫
using Common.Logging;

namespace ClassLibrary1
{
    public class Class1
    {
        private ILog log = LogManager.GetLogger<Class1>());

        public void SayHello()
        {
            this.log.Info("Hello");
        }
    }
}

再來新增一個Windows Form應用程式,並引用剛寫的庫別庫專案

簡單寫一個Button Click來呼叫類別庫中的函式
using System;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ClassLibrary1.Class1 x = new ClassLibrary1.Class1();
            x.SayHello();
        }
    }
}

因為要轉接到NLog去,所以再新增套件Common.Logging.NLog31,對應的NLog版本就是3.1
如果要對應到其他的版本,可以選擇對應的套件

加入NLog,為了方便起見,順便加入NLog.Configuration和NLog Schema for Intellisense(TM)

接下來透過設定檔把Log轉接到NLog

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <sectionGroup name="common">
            <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging"/>
        </sectionGroup>
    </configSections>
    <common>
        <logging>
            <factoryAdapter type="Common.Logging.NLog.NLogLoggerFactoryAdapter, Common.Logging.NLog31">
                <arg key="configType" value="FILE" />
                <arg key="configFile" value="~/NLog.config" />
            </factoryAdapter>
        </logging>
    </common>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
            <dependentAssembly>
                <assemblyIdentity name="NLog" publicKeyToken="5120e14c03d0593c" culture="neutral" />
                <bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0" />
            </dependentAssembly>
        </assemblyBinding>
    </runtime>
</configuration>
NLog使用預設的設定

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <!-- 
  See http://nlog-project.org/wiki/Configuration_file 
  for information on customizing logging rules and outputs.
   -->
    <targets>
        <!-- add your targets here -->
        <target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
                layout="${longdate} ${uppercase:${level}} ${message}" />

    </targets>

    <rules>
        <!-- add your logging rules here -->
        <logger name="*" minlevel="Trace" writeTo="f" />
    </rules>
</nlog>
輸出的結果




NuGet Multiple Framework 建置

NuGet使用一段時間之後,開始碰到共用的元件,在不同專案的Framework版本不同,會有引用上的困擾,在網路上找了幾個解決方案,實作之後個人覺的比較簡單的方法如下

Step1 每個版本建立一個方案檔
一般專案的命名為net20、net35、net40、net45...
其他類型的專案則再加上縮寫
Client Profile(client)
WindowsPhone(wp)
Silverlight(sl)
CompactFramework(cf)
更多完整的資料請參考官網文件
http://docs.nuget.org/docs/creating-packages/creating-and-publishing-a-package

Step2 每一個版本建立一個專案檔



Step3 每一個專案檔選擇不同的Framework,以及條件式編譯符號和修改輸出路徑
注意每個組態都要設定喔
Step4 依Framework版本,加上條件式編譯

using System;
using System.Collections.Generic;

#if NET35 || NET40 || NET45
using System.Linq;
#endif

using System.Text;

#if NET40 || NET45
using System.Threading.Tasks;
#endif

namespace ClassLibrary1
{
    public class Class1
    {
    }
}

Step5 手動建立nuget spec檔

<?xml version="1.0"?>
<package >
  <metadata>
    <id>ClassLibrary1</id>
    <version>1.0.0</version>
    <authors>xian</authors>
    <owners>xian</owners>
    <licenseUrl>http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE</licenseUrl>
    <projectUrl>http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE</projectUrl>
    <iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Package description</description>
    <releaseNotes>Summary of changes made in this release of the package.</releaseNotes>
    <copyright>Copyright 2013</copyright>
    <tags>Tag1 Tag2</tags>
    <dependencies>
      <dependency id="SampleDependency" version="1.0" />
    </dependencies>
  </metadata>
  <files>
        <file src="ClassLibrary1\**\*.cs" exclude="ClassLibrary1\obj\**\*.cs" target="src" />
  <file src="ClassLibrary1\bin\Release\net20\ClassLibrary1.dll" target="lib\net20\ClassLibrary1.dll" />
        <file src="ClassLibrary1\bin\Release\net20\ClassLibrary1.pdb" target="lib\net20\ClassLibrary1.pdb" />
  <file src="ClassLibrary1\bin\Release\net35\ClassLibrary1.dll" target="lib\net35\ClassLibrary1.dll" />
        <file src="ClassLibrary1\bin\Release\net35\ClassLibrary1.pdb" target="lib\net35\ClassLibrary1.pdb" />
        <file src="ClassLibrary1\bin\Release\net40\ClassLibrary1.dll" target="lib\net40\ClassLibrary1.dll" />
        <file src="ClassLibrary1\bin\Release\net40\ClassLibrary1.pdb" target="lib\net40\ClassLibrary1.pdb" />
  <file src="ClassLibrary1\bin\Release\net45\ClassLibrary1.dll" target="lib\net45\ClassLibrary1.dll" />
        <file src="ClassLibrary1\bin\Release\net45\ClassLibrary1.pdb" target="lib\net45\ClassLibrary1.pdb" />
    </files>
</package> 

Step6 加上測試用批次檔

@echo off
set MSBUILD=%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe
if not exist %MSBUILD% set MSBUILD=%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe
if not exist %MSBUILD% set MSBUILD=%WINDIR%\Microsoft.NET\Framework\v3.5\msbuild.exe
if not exist %MSBUILD% (
 echo MSBuild not found
 exit
) 

%MSBUILD% ClassLibrary1.net20.sln /property:Configuration=Release /m
%MSBUILD% ClassLibrary1.net35.sln /property:Configuration=Release /m
%MSBUILD% ClassLibrary1.net40.sln /property:Configuration=Release /m
%MSBUILD% ClassLibrary1.net45.sln /property:Configuration=Release /m
nuget pack ClassLibrary1.nuspec
pause


瀏覽結果