I use Common.Logging as a wrapper around NLog 2.0. I've done this so that I can replace NLog with another logging provider in the future.
I also use PostSharp to not write a try catch block everytime I need one. I have a class that inherits the OnMethodBoundaryAspect:
[Serializable]
public class LogMethodAttribute : OnMethodBoundaryAspect
{
private ILog logger;
public LogMethodAttribute()
{
this.logger = LogManager.GetCurrentClassLogger();
}
public override void OnEntry(MethodExecutionArgs args)
{
logger.Debug(string.Format("Entering {0}.{1}.", args.Method.DeclaringType.Name, args.Method.Name));
}
public override void OnExit(MethodExecutionArgs args)
{
logger.Debug(string.Format("Leaving {0}.{1}.", args.Method.DeclaringType.Name, args.Method.Name));
}
public override void OnException(MethodExecutionArgs args)
{
logger.Error(args.Exception.Message,args.Exception);
}
}
I have configured Common.Logging as follows in my web.config:
<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.NLog20">
<arg key="configType" value="FILE" />
<arg key="configFile" value="~/NLog.config" />
</factoryAdapter>
</logging>
</common>
NLog.Config looks like this:
<?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"
throwExceptions="true"
internalLogLevel="Debug"
internalLogToConsoleError="true"
internalLogFile="c:\new projects/nlog-app.txt"
>
<!--
See http://nlog-project.org/wiki/Configuration_file
for information on customizing logging rules and outputs.
-->
<targets>
<target name="database"
xsi:type="Database"
commandText="INSERT INTO LogEvent(EventDateTime, EventLevel, UserName, MachineName, EventMessage, ErrorSource, ErrorClass, ErrorMethod, ErrorMessage, InnerErrorMessage) VALUES(#EventDateTime, #EventLevel, #UserName, #MachineName, #EventMessage, #ErrorSource, #ErrorClass, #ErrorMethod, #ErrorMessage, #InnerErrorMessage)"
dbProvider="System.Data.SqlClient">
<connectionString>
Data Source=...;Initial Catalog=myDB;User Id=user;Password=pass;
</connectionString>
<installConnectionString>
Data Source=...;Initial Catalog=myDB;User Id=user;Password=pass;
</installConnectionString>
<!-- parameters for the command -->
<parameter name="#EventDateTime" layout="${date:s}" />
<parameter name="#EventLevel" layout="${level}" />
<parameter name="#UserName" layout="${identity}" />
<parameter name="#MachineName" layout="${machinename}" />
<parameter name="#EventMessage" layout="${message}" />
<parameter name="#ErrorSource" layout="${event-context:item=error-source}" />
<parameter name="#ErrorClass" layout="${event-context:item=error-class}" />
<parameter name="#ErrorMethod" layout="${event-context:item=error-method}" />
<parameter name="#ErrorMessage" layout="${event-context:item=error-message}" />
<parameter name="#InnerErrorMessage" layout="${event-context:item=inner-error-message}" />
<!-- commands to install database -->
<install-command>
<text>CREATE DATABASE myDB</text>
<connectionString> Data Source=...;Initial Catalog=myDB;User Id=user;Password=pass;</connectionString>
<ignoreFailures>true</ignoreFailures>
</install-command>
<install-command>
<text>
CREATE TABLE LogEvent(
EventId int primary key not null identity(1,1),
EventDateTime datetime,
EventLevel nvarchar(50),
UserName nvarchar(50),
MachineName nvarchar(1024),
EventMessage nvarchar(MAX),
ErrorSource nvarchar(1024),
ErrorClass nvarchar(1024),
ErrorMethod nvarchar(1024),
ErrorMessage nvarchar(MAX),
InnerErrorMessage nvarchar(MAX));
</text>
</install-command>
<!-- commands to uninstall database -->
<uninstall-command>
<text>DROP DATABASE myDB</text>
<connectionString> Data Source=...;Initial Catalog=myDB;User Id=user;Password=pass;</connectionString>
<ignoreFailures>true</ignoreFailures>
</uninstall-command>
</target>
</targets>
<rules>
<logger name="*" levels="Error" writeTo="database" />
</rules>
</nlog>
The problem is that nothing is inserted in my table. When I put a logger in for example my HomeController on the index page and I call my logger.Error("an error") it adds a record to my table.
Can somebody help me?
Are you decorating your controller methods with the LogMethodAttribute that you created?
Also, you'll want to adjust your logger rule to include more levels outside of just "Error", otherwise that's all you'll log.
Give this a try:
<rules>
<logger name="*" minLevel="Trace" writeTo="database" />
</rules>
Edit:
Have you tried moving your logger initialization into your method?
public override void OnEntry(MethodExecutionArgs args)
{
this.logger = LogManager.GetCurrentClassLogger();
logger.Debug(string.Format("Entering {0}.{1}.", args.Method.DeclaringType.Name, args.Method.Name));
}
Per Donald Belcham's Pluralsight course, aspect constructors are not executed at runtime, so perhaps your logger is not getting set properly.
add a static property logger in your class Aspect
public class LogAspect : OnMethodBoundaryAspect
{
/// <summary>
/// Gets or sets the logger.
/// </summary>
public static ILogger logger { get; set; }
set logger variable in your application init method with your ILogger class and exclude all methods before this initialization with AttributeExclude.
[LogAspect(AttributeExclude = true)]
protected void Application_Start()
{
_windsorContainer = new WindsorContainer();
ApplicationDependencyInstaller.RegisterLoggingFacility(_windsorContainer);
LogAspect.logger = _windsorContainer.Resolve<ILogger>();
Related
I am trying to create a simple example of code first with npgsql and Entity Framework but continually hit an error. Why? I have read all I can read, but have found no solution!
The credentials are fine, I can log in with PgAdmin without issues from the same machine as I'm running the C#. Tables are not created. The user is a Superuser.
When I try to .SaveChanges() I always hit the exception UpdateException: An error occurred while updating the entries. See the inner exception for details. with an inner exception of PostgresException: External component has thrown an exception.
I am completely flummexed by this. I think the most pertinant part of my code is the app.config:
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="mssqllocaldb" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="Npgsql" type="Npgsql.NpgsqlServices, EntityFramework6.Npgsql" />
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Npgsql" publicKeyToken="5d8b90d52f46fda7" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.2.2.0" newVersion="3.2.2.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<connectionStrings>
<add name="contxt" connectionString="User ID=joe;Password=test;Host=192.168.xxx.xxx;Port=5432;Database=mydb" providerName="Npgsql" />
</connectionStrings>
<system.data>
<DbProviderFactories>
<remove invariant="Npgsql" />
<add name="Npgsql Data Provider" invariant="Npgsql" description="Data Provider for PostgreSQL" type="Npgsql.NpgsqlFactory, Npgsql" />
</DbProviderFactories>
</system.data>
The actual code couldn't be simpler:
class Program
{
static void Main(string[] args)
{
using (var db = new Contxt())
{
var foo = new Foo { Name = "asdf" };
db.Foos.Add(foo);
db.SaveChanges();
}
}
}
public class Foo
{
public Int64 Id { get; set; }
public string Name { get; set; }
}
public class FooMapper : EntityTypeConfiguration<Foo>
{
public FooMapper()
{
ToTable("Foos").HasKey<Int64>(x=>x.Id);
Property(x => x.Name).HasMaxLength(255).IsVariableLength().IsRequired();
}
}
public class Contxt : DbContext
{
public DbSet<Foo> Foos { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("public");
base.OnModelCreating(modelBuilder);
}
}
I have a speciifc configuration problem.
<configuration>
<configSections>
<section name="custom" type="ConfigurationSample.CustomConfigurationSection, ConfigurationSample"/>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
</configSections>
<custom>
<customConfigurations>
<configuration id="CAT1">
<name>Tom</name>
<address type="rent">
<area>Misissipi</area>
</address>
<conifugration/>
<configuration id="Mouse1">
<name>Jerry</name>
<address type="own">
<area>Seatle</area>
</address>
<conifugration/>
<customConfigurations>
</custom>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<alias alias="IAnimal" type="MyApp.IAnimal, MyApp" />
<alias alias="CAT" type="MyApp.CAT, MyApp" />
<alias alias="Mouse" type="MyApp.Mouse, MyApp" />
<container>
<!-- should register CAT instance with name CAT1 at runtime and mapto IAnimal !-->
<!-- should register Mouse with name Mouse1 at runtime and mapto IAnimal !-->
</container>
</unity>
</configuration>
This is my app.config. All I am looking for runtime registering instances in unity container while reading the custom config section since CAT class CAT configuration in its constructor.
My classes:
public interface IAnimal
{
public string Name {get;set}
pubic bool IsLiving();
}
public class Mouse
{
MouseConfig config;
public Mouse(IAnimalConfig config)
{
this.config=config;
}
public string Name {get;set}
pubic bool IsLiving(){
//do something with config
}
}
public class Cat
{
CATConfig config;
public CAT(IAnimalConfig config)
{
this.config=config;
}
public string Name {get;set}
pubic bool IsLiving(){
//do something with config
}
}
I hope you understand where i am leading to. I need to provide config objects as parameter to the derived classes. So based on my customconfig i want to register instances in unity container. So i can work with those instances in my application. since i already know their types and name of those instances i can resolve from container.
Please let me know if i have to add anything more. Thanks
I have a simple structure of classes, interfaces as follows:
public interface IMessagingClient (interface supporting service bus queue operation)
public class ServiceBusMessagingClient : IMessagingClient (real implementation)
public class MockMessagingClient : IMessagingClient (mock implementation for our unit test)
public class FailoverMessagingClient : IMessagingClient (this implementation internally uses 2 clients and switches roles b/w 2 as and when disaster in a datacenter occur)
{
private IMessagingClient PrimaryClient { get; set; }
private IMessagingClient SecondaryClient { get; set; }
}
We load unity config from web.config/app.config and use it in our product code and test code.
We want following:
For production scenario, PrimaryClient and SecondaryClient should of type ServiceBusMessagingClient
For Test scenario, PrimaryClient and SecondaryClient should of type MockMessagingClient
Our current unity config looks like:
<container name="azure">
<register type="IMessagingClient" mapTo="FailoverMessagingClient"/>
</container>
Do we have to use some interceptors to achieve this? Or by defining a ctor in FailoverMessagingClient and using ctor injection?
Some suggestions would be great!
You can do this using named registrations.
For example, given the following example set up:
namespace ConsoleApplication8
{
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
public interface IMessagingClient { }
public class ServiceBusMessagingClient : IMessagingClient { }
public class MockMessagingClient : IMessagingClient { }
public class FailoverMessagingClient : IMessagingClient
{
private readonly IMessagingClient primaryClient;
private readonly IMessagingClient secondaryClient;
public FailoverMessagingClient(IMessagingClient primaryClient, IMessagingClient secondaryClient)
{
this.primaryClient = primaryClient;
this.secondaryClient = secondaryClient;
}
}
class Program
{
static void Main(string[] args)
{
var container = new UnityContainer().LoadConfiguration();
var failOverMessagingClient = container.Resolve<IMessagingClient>("Two");
}
}
}
you can hook up the dependencies using the app.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
</configSections>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<alias alias="IMessagingClient" type="ConsoleApplication8.IMessagingClient, ConsoleApplication8" />
<alias alias="ServiceBusMessagingClient" type="ConsoleApplication8.ServiceBusMessagingClient, ConsoleApplication8" />
<alias alias="MockMessagingClient" type="ConsoleApplication8.MockMessagingClient, ConsoleApplication8" />
<alias alias="FailoverMessagingClient" type="ConsoleApplication8.FailoverMessagingClient, ConsoleApplication8" />
<container>
<register type="IMessagingClient" name="One" mapTo="ServiceBusMessagingClient" />
<register type="IMessagingClient" name="Two" mapTo="FailoverMessagingClient">
<constructor>
<param name="primaryClient">
<dependency type="IMessagingClient" name="One" />
</param>
<param name="secondaryClient">
<dependency type="IMessagingClient" name="One" />
</param>
</constructor>
</register>
</container>
</unity>
</configuration>
Changing the line
<register type="IMessagingClient" name="One" mapTo="ServiceBusMessagingClient" />
to
<register type="IMessagingClient" name="One" mapTo="MockMessagingClient" />
will allow you to swap out your implementation of IMessagingClient as appropriate.
Personally, I would rather do this using the fluid syntax
var container = new UnityContainer();
container.RegisterType<IMessagingClient, ServiceBusMessagingClient>("One");
container.RegisterType<IMessagingClient, FailoverMessagingClient>("Two",
new InjectionConstructor(new ResolvedParameter<IMessagingClient>("One"), new ResolvedParameter<IMessagingClient>("One")));
var failOverMessagingClient = container.Resolve<IMessagingClient>("Two");
When using the unity container, you can override an existing registration by registering it again for a different class.
For example:
If you run this code:
container.RegisterType<IMessagingClient, ServiceBusMessagingClient>();
container.RegisterType<IMessagingClient, MockMessagingClient>();
The first registration is overridden and so IMessagingClient is mapped to MockMessagingClient. Its like the first line never executed.
You can use this fact, and in your unit test (in the arrange phase or in the setup method of your test class), simply register the IMessagingClient to the mock implementation like this (after loading the XML configuration):
container.RegisterType<IMessagingClient, MockMessagingClient>();
By the way, you might not want to use DI containers in unit tests. Take a look at this question.
I have a database, hbm mapping file and the App.config located in a class library. Now from a test project I reference that library and attempt to call a HibernateHelper class I create, at runtime the following error is thrown :
NHibernate.MappingException : Could not compile the mapping document: HibernateExample.Mappings.Products.hbm.xml
Please keep in mind that this is a class library that is being reference from a Test project.
If I change it output type to console application, it runs fine. But when I change it back to class library and reference it from my Test Project it throws the above mention error.
I tried adding config.Configure() but that throws a NhibernateDuplicateMapping exception.
FIXED:
Fixed the duplication mapping issue by removing from appconfig. and fixed the problem mapping entity by placing a hibernate.cfg.xml file in my Test project as well.
public sealed class NHibernateHelper
{
private static ISessionFactory _sessionFactory;
const string Connectionstring = "servicestring";
public static void OpenSession()
{
var config = new Configuration();
config.Configure();
config.AddAssembly(Assembly.GetCallingAssembly());
_sessionFactory = config.BuildSessionFactory();
}
public static ISession GetCurrentSession()
{
ISession session = null;
if (_sessionFactory == null)
OpenSession();
if (_sessionFactory != null)
{
session = _sessionFactory.OpenSession();
}
return session;
}
public static void CloseSessionFactory()
{
if (_sessionFactory != null)
{
_sessionFactory.Close();
}
}
// var dsn = ConfigurationManager.ConnectionStrings[Connectionstring].ConnectionString;
//config.SessionFactory().Integrate.Using<MsSqlCeDialect>().Connected.ByAppConfing(dsn);
// System.Diagnostics.Debug.WriteLine("My connection string: "+dsn);
//Get NHibernate configuration
//_sessionFactory = config.BuildSessionFactory();
//config.AddAssembly("HibernateExample");
}
Any ideas?
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
</configSections>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory>
<property name="connection.driver_class"> NHibernate.Driver.SqlServerCeDriver</property>
<property name="dialect">NHibernate.Dialect.MsSqlCeDialect</property>
<property name="connection.connection_string">Data Source=FirstSample.sdf;</property>
<property name="show_sql">true</property>
<mapping assembly="HibernateExample"/>
</session-factory>
</hibernate-configuration>
<connectionStrings>
<add name="testconnectionstring"
connectionString="Data Source=|DataDirectory|\FirstSample.sdf;Integrated Security=True"
providerName="Microsoft.SqlServerCe.Client.3.5" />
</connectionStrings>
<runtime>
<assemblyBinding xmlns="urnchemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Data.SqlServerCe" publicKeyToken="89845DCD8080CC91" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-9.0.242.0" newVersion="3.5.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="HibernateExample" namespace="HibernateExample.Domain" >
<class name="Product" table="Products">
<id name="Id" type="integer">
<generator class="identity"/>
</id>
<property name="Name" type="string"/>
<property name="Category" type="string"/>
<property name="Discontinued" />
</class>
</hibernate-mapping>
Exception Thrown:
Test 'NunitTest.TestClass.canquerydb' failed: NHibernate.MappingException : Could not compile the mapping document: HibernateExample.Mappings.Products.hbm.xml
----> System.InvalidOperationException : Could not find the dialect in the configuration
at NHibernate.Cfg.Configuration.LogAndThrow(Exception exception)
at NHibernate.Cfg.Configuration.AddDeserializedMapping(HbmMapping mappingDocument, String documentFileName)
at NHibernate.Cfg.Configuration.ProcessMappingsQueue()
at NHibernate.Cfg.Configuration.AddInputStream(Stream xmlInputStream, String name)
at NHibernate.Cfg.Configuration.AddResource(String path, Assembly assembly)
at NHibernate.Cfg.Configuration.AddAssembly(Assembly assembly)
at NHibernate.Cfg.Configuration.AddAssembly(String assemblyName)
NHibernateTest\NHibernateHelper.cs(21,0): at HibernateExample.NHibernateTest.NHibernateHelper.openSession()
NHibernateTest\NHibernateHelper.cs(28,0): at HibernateExample.NHibernateTest.NHibernateHelper.GetCurrentSession()
TestClass.cs(21,0): at NunitTest.TestClass.canquerydb()
--InvalidOperationException
at NHibernate.Dialect.Dialect.GetDialect(IDictionary`2 props)
at NHibernate.Cfg.Configuration.AddDeserializedMapping(HbmMapping mappingDocument, String documentFileName)
From the error, it appears that you are not configuring the Dialect before adding the mapping. This is required.
Here's a simple piece of basic configuration code:
var configuration = new Configuration();
configuration.SessionFactory().Integrate.Using<MsSql2012Dialect>()
.Connected.ByAppConfing("connName");//sic
//now you can add the mappings
I know how to use nlog to log my information in a file but now I would like to redirect my log to a ListView (C#) and do some actions. So I directed my log to a method as explained in the documentation nlog. It works.
<?xml version="1.0" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="msgbox" xsi:type="MethodCall" className="SomeNamespace.MyClass, MyAssembly" methodName="LogMethod">
<parameter layout="${level}" />
<parameter layout="${message}" />
</target>
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="msgbox" />
</rules>
</nlog>
Console.WriteLine works. It's not my problem.
namespace SomeNamespace
{
using System;
public class MyClass
{
public static void LogMethod(string level, string message)
{
Console.WriteLine("l: {0} m: {1}", level, message);
// logListView.Items.Add(Message);
// Do some other actions
}
}
}
I would like to add a line to my logListView (see commented line) but I can't because logListView is not static. How so? How do I proceed ?
One solution would be to add a static member to MyClass, like this:
public class MyClass
{
public static ListView MyListView { get; set; }
public static void LogMethod(string level, string message)
{
Console.WriteLine("l: {0} m: {1}", level, message);
var logListView = MyListView;
if (logListView != null) {
logListView.Items.Add(Message);
}
// Do some other actions
}
}
You can set the value of MyListView from some other part of your application when it is available.
While this solution would work, I would not prefer it because it is counter-intuitive. What you are doing here is declaring in static configuration a log target that is not meaningful at all in a static context: you want to log to a UI control that has not been created, there is no good way to refer to it until the application's UI has been shown, and the UI will be shown at some point or (academically speaking) maybe not at all.
I believe it is preferable to create your own log target class deriving from Target or TargetWithLayout. You can pass any parameters necessary (e.g. the ListView instance) to the log target's constructor, and add the log target programmatically at the point where the values of these parameters become known (i.e. the UI is shown and we have a ListView we can refer to).