First line empty in Razor

First of all, I never thought a problem so simple would give me such a hard time!

My Problem

I’m using Razor views to generate some XML. I know I should probably use some sort of Serializer/Deserializer for that kind of job, but I needed something easier to change and preferably something that doesn’t need to be compiled. The problem is an empty line before my content which off course makes it invalid.

The code looks like:

@{
Response.ContentType = "text/xml";
}
<?xml version="1.0" encoding="UTF-8" ?>
...

and here is how the output is generated:

Empty line before content

First Try

The first thing I tried was to move the <xml> tag to the line above getting rid of the new lines that could possibly have.

@{
Response.ContentType = "text/xml";
}<?xml version="1.1" encoding="UTF-8" ?>
...

I even moved the Razor block to the bottom…

<?xml version="1.1" encoding="UTF-8" ?>
...
@{
Response.ContentType = "text/xml";
}

Nothing!

Second Try

Ok. This first line is not in my code. Something is putting it there. No problem! I can create a Response Filter and change the output removing this empty line.

using System.IO;
using System.Text;
using System.Web.Mvc;

namespace MyWebsite.Helpers
{
    public class RemoveEmptyLineWriter : MemoryStream
    {
        private readonly Stream filter;

        public RemoveEmptyLineWriter(Stream filter)
        {
            this.filter = filter;
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            var content = Encoding.UTF8.GetString(buffer);
            content = RemoveFirstEmptyLine(content);
            filter.Write(Encoding.UTF8.GetBytes(content), offset, Encoding.UTF8.GetByteCount(content));
        }

        private static string RemoveFirstEmptyLine(string content)
        {
            var firstLineIsEmpty = content.Substring(0, 2) == "\r\n";
            return firstLineIsEmpty ? content.Substring(2, content.Length - 2) : content;
        }
    }

    public class EmptyLinesRemoverFilter : ActionFilterAttribute
    {
        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            base.OnResultExecuted(filterContext);
            var response = filterContext.HttpContext.Response;
            response.Filter = new RemoveEmptyLineWriter(response.Filter);
        }
    }
}

 

[EmptyLinesRemoverFilter]
public ActionResult Index()
{
  return View();
}

This code I found here, and then I changed it a little bit.

It simply adds to the Response a Filter which is invoked after the output is generated. So I can get it, modify and write again to the buffer.

I think this would have worked just fine if it wasn’t for my IIS being configured to Gzip the document. With Gzip enabled, after I read the buffer the content is just a bunch of messy characters. Decompressing the content and then compressing again is not a solution as it would cause an unnecessary overhead in my application. I’d rather turn Gzip off for those type of files but only if I really had to.

I also tried changing the order that my filter is added by changing the OnResultExecuted to OnActionExecuting but it doesn’t affect the order that the filter is executed, only the order in which it’s added to the response, which makes no difference.

My next try would be creating an IHttpModule, but I wanted something easier and something that I didn’t have to intercept all my requests.

Solution 1

Maybe you were lucky and the previous solutions worked for you, but in case they don’t, here is what worked for me. I had to go deeper in MVC and change the hierarchy of which the rendering is executed.

I ended up with this:

using System.Web.Mvc;
using System.Web.WebPages;

namespace MyWebsite.Helpers
{
    public class RazorXmlViewPage<T> : WebViewPage<T>
    {
        public override void ExecutePageHierarchy()
        {
            Response.ContentType = "text/xml";
            Layout = null;
            PushContext(new WebPageContext(), Response.Output); // push a new page context to the stack
            base.ExecutePageHierarchy();
        }

        public override void Execute()
        {

        }
    }

    public class RazorXmlViewPage : RazorXmlViewPage<object>
    {

    }
}

and in my Razor view…

@inherits RazorXmlViewPage<IEnumerable<string>>
<?xml version="1.0" encoding="UTF-8"?>

Thanks to this post that provided a source code that helped me get to this one.

The Razor view file inherits the WebViewPage by default. This page tells Razor that it inherits from a different class, in which I can override the execution of its core methods. We also have to override the Execute method because it is abstract.

It turns out I din’t even have to modify the output. Just by pushing a new WebPageContext to the stack the page rendered without the blank line.

But, if wanted, I could do some cools things with the Output. Take this code for instance:

public override void ExecutePageHierarchy()
{
    StringWriter writer = new StringWriter();
    PushContext(PageContext, writer);
    base.ExecutePageHierarchy();
    PopContext();

    Response.Clear();
    string output = writer.ToString();
    output = output.Replace("<body>", "<body><h1>An Example of Filtering Razor Output</h1>");
    Response.Write(output);
    Response.End();
}

If you want to understand better the methods used in the code above, take a look at the WebViewPage source code.

Solution 2

Another solution is to Render your View as a string, using the method bellow, change it and set the Response to your new content.

public string RenderRazorViewToString(string viewName, object model)
{
  ViewData.Model = model;
  using (var sw = new StringWriter())
  {
    var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
    var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
    viewResult.View.Render(viewContext, sw);
    viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
    return sw.GetStringBuilder().ToString();
  }
}

You know when you use return View(model);. This method it’s actually an alias to return new ViewResult {}. What the code above is doing is using the same implementation of that class, as you can see in the MVC source, in the method ExecuteResult.

I knew that I could use this code when dealing with this problem, but as I was looking at that class, I felt bad copying that much code from the MVC source and pasting it into my code. What if MVC updates as it does often and change that code? I’ll have to copy and paste it again in case this bug remains not fixed. So, for my use case I used the first solution as is less code copied and rewrote, plus, I didn’t even have to remove the first line from my output since the change skipped the bug. For other use cases the second solution might suit better your need/taste.

Please comment here what worked for you.

Advertisements

Enterprise Library 5 with ODP.NET

Enterprise Library 5 with Oracle

Introduction

This tutorial is an update from my previous post Enterprise Library 5 with Oracle Cursor, in which I demonstrated how to use Enterprise Library 5 with Oracle but NOT using ODP.NET, using MS Client instead. That’s because ODP.NET wasn’t compatible with Enterprise Library 5 when I wrote that post.

Well, luckily things have changed and now we can use them together, so, I created this step-by-step tutorial to show you how you can setup your project to use Enterprise Library 5 with ODP.NET. The steps shown here were tested on Oracle 11g, Enterprise Library 5, ODP.NET 11.1.0.7.20, and EntLibContrib 5. Different versions of Oracle and ODP.NET may work as well.

Step 1 – Environment

Oracle

I assume you already have some Oracle installed, but in you case you don’t you can download a Pre-built Virtual Machine that will make your life easier when setting up the environment.

Oracle Data Provider for .NET – ODP.NET

It will install the .NET client which communicates with the database – pretty obvious, I know, sorry for that. You can download it here.

I recommend you to really install it and not just copy the DLLs. I’m saying because I tried it. And it works! I just don’t think it’s worth having to copy DLLs with hundreds MBs into your project. In case you still want opt for that, you will need to copy the DLLs from Oracle Instant Client into your project’s bin folder.

Step 2 – Installing Libraries

I’m going to start by creating a new Project, going to File, New Project…New project window

Give the project a name and now, we install the libraries. I’m going to do that by using NuGet. It’s the easiest and fastest way and if you’ve been avoiding using NuGet all this time, then you should stop doing that!

From the NuGet Package Manager Console, run the following command:
Install-Package EntLibContrib.Data.OdpNetInstalling ODP.NET via NuGet Command

Or, you can right click the project and click on Manage NuGet PackagesInstalling ODP.NET via NuGet Window

For those who prefer manually install everything, download the EntLibContrib and add the necessary assembly references to the project.

Also, add a reference the Oracle.DataAccess.dll (you can find it in your oracle folder), usually c:\oracle\product\11.x.xx.x\odp.net\bin.
Adding Oracle Client library

In the end, regardless the installation type you chose, you should have your references as shown below:
References added to the project

Step 3 – Configuration

In the Web.Config / App.config, we need to tell Enterprise Library not to use its default implementation of Oracle Client and use the EntLibContrib one, which will work with ODP.NET. The code below does that by setting the Provider Mapping:

<configuration>
  <configSections>
    <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
  </configSections>
  <dataConfiguration defaultDatabase="DefaultConnectionString">
    <providerMappings>
      <add databaseType="EntLibContrib.Data.OdpNet.OracleDatabase, EntLibContrib.Data.OdpNet, Version=5.0.505.0, Culture=neutral, PublicKeyToken=null" name="Oracle.DataAccess.Client"/>
    </providerMappings>
  </dataConfiguration>
</configuration>

After that, also add the Connection String to your database, below is an example:

<connectionStrings>
    <add name="DefaultConnectionString" connectionString="Data Source=127.0.0.1;User ID=scott;Password=tigger;Persist Security Info=True;" providerName="Oracle.DataAccess.Client"/>
</connectionStrings>

If you have problems configuring your connection string, see more different ways of setting it here.

Step 4 – Code

At this point, everything is set up and we can start coding. The code is pretty simple and it’s just to illustrate the concept.

First, I’m going to create a User class that will hold the user’s info.

using System;

namespace EntLib5ODP.NET
{
    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public DateTime? BirthDate { get; set; }
        public string Phone { get; set; }
    }
}

Now, we need to ask Enterprise Library for a Database object. That Database object contains the methods that allows us to talk to the database. The line that does that is this one:

var database = EnterpriseLibraryContainer.Current.GetInstance<Database>();

With that object, we are able to call the method ExecuteReader which queries the database. One of the overloads of that method expect a Stored Procedure name and the arguments of that procedure. It will use the order of the arguments to bind them. My stored procedure has 3 arguments: id, name and result. Notice, we need to supply all parameters, so we set the ones we don’t want as null just to satisfy the parameters count, otherwise we would receive the error “The wrong number of parameters does not match number of values for stored procedure”. Here’s how we call the procedure to return a User by Id.

database.ExecuteReader("pkg_client.sp_list", id, null, null));

This will return an IDataReader, which is a HashTable with some helper methods. Now let’s put all together:

using System;
using System.Data;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Data;

namespace EntLib5ODP.NET
{
    public class UserData
    {
        private readonly Database database;

        public UserData()
        {
            database = EnterpriseLibraryContainer.Current.GetInstance<Database>();
        }

        public User GetById(int id)
        {
            User user = null;

            using(var reader = database.ExecuteReader("pkg_client.sp_list", id, null, null))
            {
                if (reader.Read())
                    user = MapUser(reader);
            }
            return user;
        }

        private static User MapUser(IDataReader reader)
        {
            var user = new User
            {
                Id = (int)reader["id"],
                Name = (string)reader["name"],
                Email = reader["email"] as string,
                BirthDate = reader["birthdate"] as DateTime?,
                Phone = reader["phone"] as string
            };
            return user;
        }
    }
}

and the program running…
Program running

Download Sample

The links below contain the sample code with all that I showed you here. If you also want to test it on your machine, you need to download the SQL scripts and execute them in your database. The scripts will create a table with 3 items and a package with one procedure to list the items from that table. In case you’re using an schema, don’t forget to set them as well.

Dropbox => http://dl.dropbox.com/u/6963935/samples/EntLib5_ODP.NET/EntLib5ODP.NET.zip
GitHub => https://github.com/stanleystl/EntLib5ODP.NET
Scripts SQL => http://dl.dropbox.com/u/6963935/samples/EntLib5_ODP.NET/scripts.zip

Other Download Links

NuGet – http://nuget.codeplex.com/
Enterprise Library – http://entlib.codeplex.com/
EntLibContrib – http://entlibcontrib.codeplex.com/
ODP.NET – http://www.oracle.com/technetwork/topics/dotnet/index-085163.html
Oracle – http://www.oracle.com/technetwork/database/express-edition/overview/index.html
Pre-built Oracle Virtual Machine – http://www.oracle.com/technetwork/community/developer-vm/index.html

Shared Client and Server configuration with custom ActionResult – Solving it in a DRY way

I’m developing a MVC application and there are some configurations I want to use both on client and server side but I don’t want to replicate them, I want it be DRY (Don’t Repeat Yourself). Having it gives me the hability of changing some value on both sides without deploying the application again.

I could have created my properties in my AppSettings section and then print the variables on a page, but the AppSettings would become huge and the page header a mess.

Here is the solution I end up with. I created a JSON file containing my propeties, like so:

common.json

{
	"highlightProductId": 5,
	"bannerEnabled": false,
	"passwordLength": 15,
	"adURL": "http://google.com/ad"
}

That allows me to use the Newtonsoft or any other JavaScript parser like the JavaScriptDeserializer from .Net and have that JSON as a class. You can also deserialize it as “dynamic” if you are using the Newtonsoft library.

Well, that solves the problem for the server side. The client side though would have to call jQuery.getJSON to be able to read that file but that slows the page loading down and doesn’t give the user a nice experience because the user has to wait until the ajax call gets finished, so it can continue processing the rest of the script.

What I did was to turn that JSON into a JS file. To do that, you just have to assign that JSON to a variable and then you can embed the result in the page as a JavaScript file!

var common = { };

That is a valid JS file!

Now let’s teach MVC how to do that. Create the file below:

namespace System.Web.Mvc
{
    using System;

    public class JsonToJavaScriptResult : ActionResult
    {
        public string Prefix { get; private set; }
        public string JsonFile { get; set; }

        public JsonToJavaScriptResult(string prefix, string jsonFile)
        {
            JsonFile = jsonFile;
            Prefix = prefix;
        }

        public override void ExecuteResult(ControllerContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            HttpResponseBase response = context.HttpContext.Response;
            response.ContentType = "application/x-javascript";

            response.Write(Prefix);            
            response.WriteFile(JsonFile);
        }
    }
}

There we are creating a custom ActionResult that concatenates the prefix – which are the part that will hold our variable name – with the content of the file – our JSON – and writes it all to the page buffer.

Now let’s make our Controller that will use the newly created class.

    public class SharedController : Controller
    {        
        //
        // GET: /Shared/Script

        public JsonToJavaScriptResult Script()
        {
            const string fileName = "common.json"
            const string prefix = "var Shared = ";
            var jsonFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);

            return new JsonToJavaScriptResult(prefix, jsonFile);
        }
    }

The last step is just insert the script tag in your page that will embed our code.

<script src="@Url.Action("Script", "Shared")" type="application/x-javascript"></script>

and you can do something like that

<script type="text/javascript">
  alert(Shared.highlightProductId);
</script>

Any new ideas or improvements are welcome.

How to Fix “HTTP Error 403.14 – Forbidden The Web server is configured to not list the contents of this directory”

This error occurs when you have MVC 2+ running hosted on IIS 7+, this is because ASP.NET 4 was not registered in IIS. In my case I was creating a MVC 3 project and hosting it on IIS 7.5.

To fix it, make sure you have MVC 2 or above and .Net Framework 4.0 installed, then run a command prompt as administrator and type the following line:

32bit (x86)

%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe -ir

64bit (x64)

%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_regiis.exe -ir

Creating your own Pattern Layout Converter for Log4net

Pattern Layout Converter is the way you tell log4net how to log something that it doesn’t know yet.

You first create your class that will get the information, for instance, this class will is to log the machine name:

using System;
using System.IO;
using log4net.Layout.Pattern;

namespace MyApplication.Logging
{
    public class MachinePatternConverter : PatternLayoutConverter
    {
        protected override void Convert(TextWriter writer, log4net.Core.LoggingEvent loggingEvent)
        {
            writer.Write(Environment.MachineName);            
        }
    }
}

Then, you edit your config file adding the converter you just created:

  <log4net>
    <appender name="Application" type="log4net.Appender.FileAppender">
      <file value="log\application.log" />
      <appendToFile value="true" />
      <maximumFileSize value="1024KB" />
      <layout type="log4net.Layout.PatternLayout">        
        <converter>
          <name value="machine" />
          <type value="MyApplication.Logging..MachinePatternConverter" />
        </converter>        
        <conversionPattern value="%date [%thread] %level %logger %machine - %message e:%exception%newline %newline" />
      </layout>
    </appender>
<!-- lines removed for brevity -->

In the code above, we added our new converter and named it “machine”. Then, In the conversionPattern line, we can use it wherever we want by adding the %machine variable.

Here are others converters you may want to use:

    public class IPPatternConverter : PatternLayoutConverter
    {
        protected override void Convert(TextWriter writer, log4net.Core.LoggingEvent loggingEvent)
        {
            if (HttpContext.Current != null)
            {
                writer.Write(HttpContext.Current.Request.UserHostAddress);
            }
        }
    }
    public class UrlPatternConverter : PatternLayoutConverter
    {
        protected override void Convert(TextWriter writer, log4net.Core.LoggingEvent loggingEvent)
        {
            if (HttpContext.Current != null)            
                writer.Write(HttpContext.Current.Request.Url.AbsoluteUri);
        }
    }
    public class UserAgentPatternConverter : PatternLayoutConverter
    {
        protected override void Convert(TextWriter writer, log4net.Core.LoggingEvent loggingEvent)
        {
            if (HttpContext.Current != null)
            {
                writer.Write(HttpContext.Current.Request.UserAgent);
            }
        }
    }

Now, applying all converter in our config file:

  <log4net>
    <appender name="Application" type="log4net.Appender.FileAppender">
      <file value="log\application.log" />
      <appendToFile value="true" />
      <maximumFileSize value="1024KB" />
      <layout type="log4net.Layout.PatternLayout">
        <converter>
          <name value="url" />
          <type value="MyApplication.Logging.UrlPatternConverter" />
        </converter>
        <converter>
          <name value="ip" />
          <type value="MyApplication.Logging.IPPatternConverter" />
        </converter>
        <converter>
          <name value="machine" />
          <type value="MyApplication.Logging.MachinePatternConverter" />
        </converter>
        <converter>
          <name value="userAgent" />
          <type value="MyApplication.Logging.UserAgentPatternConverter" />
        </converter>
        <conversionPattern value="%date [%thread] %level %logger %url %ip %machine %userAgent - %message e:%exception%newline %newline" />
      </layout>
    </appender>

Do you have any interest Pattern Layout Converter you use in your application?

Logging to multiple files – Log4Net

I am going to explain how to log using Log4Net and how to separate the different types of logs from your application into different output files. The main focus of this post is not explain how log4net works in detail, however if your are interesting about learning more about it I recommend this article http://www.codeproject.com/KB/dotnet/Log4net_Tutorial.aspx.

The purpose here is to separate the log by source, for instance, caching log in one file, queries in another file, application log in another one, and also a single file for logging errors from all sources, this way we can find errors easier. The errors will still be logged in the library’s log though, because we may want to focus on that library specifically.

Take a look at this configuration file and will explain where the separation comes up later:

<?xml version="1.0" encoding="utf-8" ?>
<log4net>
  <appender name="Application" type="log4net.Appender.FileAppender">
    <file value="log\application.log" />
    <appendToFile value="true" />
    <maximumFileSize value="1024KB" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
    </layout>
  </appender>

  <appender name="ErrorLog" type="log4net.Appender.RollingFileAppender">
    <file value="log\error.log" />
    <rollingStyle value="Date" />
    <appendToFile value="true" />
    <datePattern value="ddMMyyyy" />
    <maxSizeRollBackups value="10" />
    <filter type="log4net.Filter.LevelRangeFilter">
      <levelMin value="ERROR"/>
    </filter>
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
    </layout>

  </appender>

  <appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
    <bufferSize value="1" />
    <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <connectionString value="data source=127.0.0.1;initial catalog=Application_Log_Database;integrated security=false;persist security info=True;User ID=abc123;Password=abc123" />
    <!-- AppId parameter comes from the table Applications -->
    <commandText value="INSERT INTO application_log ([date],[thread],[level],[logger], [message], [exception]) VALUES (@log_date,@thread,@log_level,@logger, @message,@exception)" />

    <filter type="log4net.Filter.LevelRangeFilter">
      <levelMin value="ERROR"/>
      <levelMax value="FATAL"/>
    </filter>

    <parameter>
      <parameterName value="@log_date" />
      <dbType value="DateTime" />
      <layout type="log4net.Layout.RawTimeStampLayout" />
    </parameter>

    <parameter>
      <parameterName value="@thread" />
      <dbType value="String" />
      <size value="255" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%thread" />
      </layout>
    </parameter>

    <parameter>
      <parameterName value="@log_level" />
      <dbType value="String" />
      <size value="50" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%level" />
      </layout>
    </parameter>

    <parameter>
      <parameterName value="@logger" />
      <dbType value="String" />
      <size value="255" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%logger" />
      </layout>
    </parameter>

    <parameter>
      <parameterName value="@message" />
      <dbType value="String" />
      <size value="4000" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%message" />
      </layout>
    </parameter>

    <parameter>
      <parameterName value="@exception" />
      <dbType value="String" />
      <size value="4000" />
      <layout type="log4net.Layout.ExceptionLayout" />
    </parameter>    

  </appender>

  <appender name="OpenRasta" type="log4net.Appender.FileAppender">
    <file value="log\openrasta.log" />
    <appendToFile value="true" />
    <maximumFileSize value="1024KB" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
    </layout>
  </appender>

  <appender name="Messaging" type="log4net.Appender.FileAppender">
    <file value="log\messaging.log" />
    <appendToFile value="true" />
    <maximumFileSize value="1024KB" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
    </layout>
  </appender>

  <appender name="Queries" type="log4net.Appender.FileAppender">
    <file value="log\queries.log" />
    <appendToFile value="true" />
    <maximumFileSize value="1024KB" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %-5level [%property{NDC}] - %message%newline" />
    </layout>
  </appender>

  <appender name="Memcached" type="log4net.Appender.FileAppender">
    <file value="log\memcached.log" />
    <appendToFile value="true" />
    <maximumFileSize value="1024KB" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %-5level [%property{NDC}] - %message%newline" />
    </layout>
  </appender>

  <root>
    <level value="All" />
    <appender-ref ref="ErrorLog" />
    <appender-ref ref="AdoNetAppender" />
  </root>

  <logger name="Log4NetExample">
    <level value="INFO" />
    <appender-ref ref="Application" />
  </logger>

  <logger name="OpenRasta">
    <level value="INFO" />
    <appender-ref ref="OpenRasta" />
  </logger>

  <logger name="Spring">
    <level value="WARN" />
    <appender-ref ref="Messaging" />
  </logger>
  <logger name="NServiceBus">
    <level value="WARN" />
    <appender-ref ref="Messaging" />
  </logger>

  <logger name="System.Data.Linq">
    <level value="DEBUG" />
    <appender-ref ref="Queries" />
  </logger>

  <logger name="Enyim.Caching.Memcached">
    <level value="WARN" />
    <appender-ref ref="Memcached" />
  </logger>

</log4net>

Don’t be scared! It may look big, but that is because I’m showing a configuration with a lot of libraries and the AdoNetAppender is a little big too. What this configuration is doing is creating the Appenders, setting the root section, and then setting the level things will be logged with the loggers section.

The Appenders are most of them logging into text files, and one is logging into the database. In order to have the errors from all sources, notice we are adding the ErrorLog appender and the AdoNetAppender in the root section. This is because all the loggers must inherit those two. All the loggers will log their errors in a text file and in the database:

<root>
	<level value="All" />
	<appender-ref ref="ErrorLog" />
	<appender-ref ref="AdoNetAppender" />
</root>

The root’s log level is set to “All“, so if you don’t specify any level to a logger, it will inherit from the root and its value will be All as well.

If you look at those two appenders we are filtering their minimum level types as ERROR in the appender itself.

<appender name="ErrorLog" type="log4net.Appender.RollingFileAppender">    
	<filter type="log4net.Filter.LevelRangeFilter">
	  <levelMin value="ERROR"/>
	</filter>
...

This is how we carry the error loggers along with the other loggers but logging only the errors. The libraries are filtered by their namespace, for instance Enyim.Caching.Memcached, and each library has its own logger set with a specific level of logging.

Log4net is a well known library and most of other libraries support it by default. For those libraries that doesn’t, for example, LinqToSql, a quick search on Google can give you the code to make it supported.

How to clear the DataContext cache on LinqToSql

When you get data using LinqToSql and change something in the object, you expect that calling get object again will invalidate the cache and return the new objects, but it doesn’t! LinqToSql will return a reference of the object, what means, it will return the same object you had before.

The code below force LinqToSql to get new object(s), not the one(s) it has in memory:

public Order Get(int id)
{
	var order = Context.Orders.SingleOrDefault(o => o.orderId == id);
	
	if (order != null)
		// invalidate cache
		Context.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, order);

	return order;
}