Sunday, July 21, 2013

C#/VB.NET Optional Parameters and the MissingMethodException Exception

Optional Parameters 

Optional parameters is a useful feature in C# and VB.NET languages. Adding an optional parameter to a method can sometimes make re-factoring a bit easier and less invasive. There is however a catch one should know. I ran into this situation a few days ago and here is my attempt to describe it:

Initially

Suppose you have a library, let's call it OptionsLib. In this class library lets say we have class called Common. In this Common class there is a method call DoSomeWork whose signature looks initially like

public void DoSomeWork(){
   DoStepOne();
   DoStepTwo();
   DoSomeOtherStep();

}

Now we have a consumer of this OptionsLib library and let's call it OptionsClient and it exists in its own assembly. So we have two assemblies: OptionsLib v1.0.0.0 and OptionsClient v1.0.0.0.

New Version: Minor Change

You've decided to make a minor change to your OptionsLib.Common class. Namely you wanted to add some conditional logic to the DoSomeWork method. So the new method would look something like:

public void DoSomeWork(bool someCondition = true){
   DoStepOne();
   DoStepTwo();
   if(someCondition){
       DoSomeOtherStep();
   }
}

There are probably other libraries that depend on the OptionsLib library so making the new parameter optional alleviates you from having to change the way the method called everywhere. The existing behavior is retained by making the new parameter optional and giving it a default value of true. So now re-compiling the whole solution will yield no errors as a result of the new optional parameter. The compiler will realize the new parameter is optional and will take care of passing the default value for you everywhere the method DoSomeWork is called.

The Issue: System.MissingMethodException

Let's say you found a bug in some of the libraries that use OptionsLib library or a change is made to one of its clients and you wanted to push that change to existing installations. In our example, suppose we may have fixed some bug or added a feature to the OptionsClient.dll assembly. So now OptionsClient.dll is compiled against the new version of OptionsLib, the version with the optional parameter change. In the existing installations however, the OptionsLib does not have the optional parameter we added.

For the most part placing the new OptionsClient.dll assembly in existing installations will be OK. It will find its referenced assemblies in the existing installations and everything seems to work fine. Until it starts calling the method DoSomeWork which in the new version has an optional parameter but not in the existing version. So in reality the new OptionsClient call of DoSomeWork looks like:
...DoSomeWork(true); // my understanding is that the compiler passes true for you                                               // because it's optional and the default is true
When the above call is made the runtime will complain because there is no method named DoSomeWork in v1.0.0.0 of OptionsLib that takes a boolean; there is one with no parameters at all but it's not what was called. The runtime then throws the System.MissingMethodException exception. So you'll realize that you may need to also recompile and ship the OptionsLib v1.0.0.1 the one with optional parameter

I Learned

Optional parameters are useful but sometimes adding them to a library can break dependents assemblies on this the changed library when the dependent assemblies are deployed alone without the changed library. I think I'd prefer method overloading when re-factoring.

http://msdn.microsoft.com/en-us/library/dd264739.aspx optional parameters
http://msdn.microsoft.com/en-us/library/zk1a255s(v=vs.80).aspx MissingMethodException

 

Sunday, June 2, 2013

Entity Framework Code First Does Not Create Database

Where is the Database?

I spent more time than I should have trying to troubleshoot why my database not being created. My DbContext-based class looked like:

    public class TakeNoteContext : DbContext
    {
        public TakeNoteContext()
            : base("name=TakeNote")
        {
            
        }
        public DbSet Posts ;
        public DbSet Users;
        public DbSet PostTypes;
        public DbSet SourceTypes;

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            //base.OnModelCreating(modelBuilder);
            //an alternative to using attributes
            modelBuilder.Configurations.Add(new PostConfiguration());
        }
    }

Everything looked right to me, initially. And later I noticed that I was using fields and properties for my DbSet data members.

The correct way:

    public class TakeNoteContext : DbContext
    {
        public TakeNoteContext()
            : base("name=TakeNote")
        {
            
        }
        public DbSet Posts { get; set; }
        public DbSet Users { get; set; }
        public DbSet PostTypes { get; set; }
        public DbSet SourceTypes { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            //base.OnModelCreating(modelBuilder);
            //an alternative to using attributes
            modelBuilder.Configurations.Add(new PostConfiguration());
        }
    }

The interesting thing is that the database can be created if I call ctx.Database.CreateIfNotExists(); directly even if I used fields. There might other reasons why your database is not created. My sure your connection is correct, for example.

Monday, May 27, 2013

WordPress Links not Working after Site Move

Reset Permlinks

I helped moving a wordpress blog from one directory to another (from a directory to its parent) and after the move, all links stopped working and returned a 500 Internal Server Error. Notice it was not a 404 file not found error.

After some search, it was suggested on a forum (sorry I don't have the link) that reset permlinks fixes the issue. This is important if the site url and home changes. Basically from Settings -> Permlinks , hit Save. This will cause all permlinks to reflect the new url.

Having all links broken was scary. I hope this tip helps someone.


Thursday, May 2, 2013

Architecting .NET Applications for the Enterprise

Microsoft® .NET: Architecting Applications for the Enterprise (amazon)


A great book, I think, on software architecture using the .NET framework


The first part of the book is on Principles of software architecture. The seconds part is on the "Design of the System". This second part is then divided into a number of chapter. Each chapter is dedicated to one layer of the system. Business layer, Service layer, Data Access Layer etc.

My notes here are on the design of the business layer. The authors presented a number of patterns starting with the simplest and progressing to the most complex one that's suited to applications where the business logic involves much more that data insertion and retrieval.

BLL Patterns

Transaction Script Pattern

Think of an ASP.NET page with controls whose events are handled by code-behind (or MVC actions) code. The code then interacts with data store according following a script of known steps. This is a very simple pattern with no object-oriented design.

Command Pattern

The authors then talk about the command pattern as one step above the TS pattern. Each action that the system does is incapsulated in a class with a common interface. What's interesting here is that since actions are represented as classes, actions or a series of them that participating in a transaction, can be serialized.

Table Module Pattern

What's interesting about this pattern is that the BLL logic is grouped into components each of which deal with one entity. The component or class does not represent the entity but rather serves as a gateway to the table holding the instances of that entity in the database. Code following this pattern tends to be heavy on DataSet or similar data container but not a generic .NET container. DataSets are awful. 

Table Data Gateway Pattern

In this pattern, another layer is added between the BLL logic and the code directly talks to the database, hence Gateway.

Active Record Pattern

Each data entity is represented by class. Unlike the TM pattern, what is represented here is the individual rows and not the entire table. This allows for use of .NET generic containers. 

A class represents a row and all the logic that can be done on that data. The data handling (read,write, update and deleted) can be done either with this class or in separate DAL specific class.

The simplicity of this pattern, its cleanliness and its strongly-typed nature of representing entities make it a good choice for applications that are not very complex. Have said that however, I recommend taking a look at http://misko.hevery.com/2009/06/29/active-record-hard-to-test/.

Interestingly, the authors talk about LINQ-to-SQL and how it can be considered an Active Record pattern implementation.

Domain Model Pattern

When the complexity of a system grows and business logic involves operations that far exceed interactions with the database, the DM pattern is ideal. The focus here is on modeling the domain problem into a set of interconnected objects. The focus is also on the logic and interactions between these objects with no regard (at least at the BLL) to how data is persisted. 

Summary

A few patterns caught my interest while reading the Microsoft® .NET: Architecting Applications for the Enterprise. These patterns are primarily used when designing the business logic layer. Patterns discuss include, Transaction Script, Table Module, Active Record and Domain Model.


 


Sunday, October 14, 2012

Web App Restarting Unexpectedly


What happened?


This was an ASP.NET application. It used forms authentication. The user logs in, navigates to a number of pages here and there and suddenly upon hitting few particular pages, the web app would restart. I knew this because 1) the user lost session 2) logs that are typically collected at Application_Start.

This was rather a puzzling and mysterious behavior of an app that's worked with no such issue for many months.

The Cause:


There was a piece of code in those few pages that wrote to a config file (a file whose extension is .config but not web.config). This was IIS6. This change to this config file triggered the AppPool to recycle and thus the application to restart.

The fix is obviously simple: don't write to the config file.

Saturday, April 21, 2012

Another log4net HowTo


Intro and Configuration
Log4net is a sophisticated logging library for .NET applications (web or otherwise). It’s not however cumbersome to use, neither it’s intrusive I believe. I will try in this post to illustrate what I think is good configuration for this library. A configuration that lets a .NET application uses but not have a hard dependency on it.
You start by downloading the library here http://logging.apache.org/log4net/. There you’ll also find good examples and documentation. Add a reference to your .NET app.
Now there are a number of ways you can configure the library, what to log (date & time stamp, thread #, custom message, exceptions etc) and where to log (a database, a file or the standard output {console}). A good way to configure the library is tell your application and the assembly level where the configuration file for log4net (typically an XML file) lives. You do so by adding the below line to your AssemblyInfo.vb or (AsssemblyInfo.cs) class
<Assembly: log4net.Config.XmlConfigurator(ConfigFile:="MyAppLog4net.config", Watch:=True)>

The configFile can a full-path to your log4net configuration file. The watch flag if set true tells log4net to reload the configuration at runtime if the configuration file was changed.
Now technically you can start logging. Given the simple config file below
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
  <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
    <file value="myLog.log" />
    <appendToFile value="true" />
    <maximumFileSize value="100KB" />
    <maxSizeRollBackups value="2" />

    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date %level %thread %logger - %message%newline" />
    </layout>
  </appender>

  <root>
    <!--<level value="DEBUG" />-->
    <appender-ref ref="RollingFile" />
  </root>
</log4net>
With this log file we can log a visit to web page

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    log4net.LogManager.GetLogger(Me.GetType().Name).Info(Me.Request.Path + " visited.")
End Sub
A sample output: 2012-04-21 09:21:33,970 INFO 21 default_aspx - /Default.aspx visited.
A better approach (create your own wrapper):
Instead of invoking log4net directly from your business logic layer, data layer, etc. a better approach is to create wrapper logging layer. The benefit is that you decouple your application from a specific logging implementation.
One way to do this is to create an interface that defines your logging operations. A simple interface can look like the below.
Public Interface ICustomLog
    Sub Debug(ByVal source As Type, ByVal message As String, ByVal exception As Exception, ByVal customObject As CustomLogProperties)
    Sub Info(ByVal source As Type, ByVal message As String, ByVal exception As Exception, ByVal customObject As CustomLogProperties)
    Sub Warn(ByVal source As Type, ByVal message As String, ByVal exception As Exception, ByVal customObject As CustomLogProperties)
    Sub [Error](ByVal source As Type, ByVal message As String, ByVal exception As Exception, ByVal customObject As CustomLogProperties)
    Sub Fatal(ByVal source As Type, ByVal message As String, ByVal exception As Exception, ByVal customObject As CustomLogProperties)
End Interface

Any type of logging implementation will then have to adhere to the defined interface. The parameters passed to various logging methods will apparent later, hopefully.
Here is an implementation that will rely fundamentally on log4net. But before showing the concrete implementation, let’s talk about custom properties that you can tell log4net to log for you.
Logging Custom Properties using log4net [.Core.LoggingEvent]
By default log4net will log a number of properties (thread number, date of event, custom message etc.). If you wish to add properties that are specific to your application, log4net will let you do that through a number of ways. One of the ways that you can load a log4net logger object with custom properties is through using the LoggingEvent class. The sample code will illustrate how. One of the common issues one runs to when using custom properties is that even it appears the code is using them correctly, they don’t show in the log file/ log table etc. This is almost always due to the fact that configuration file is not written correctly to tell log4net how to render or from where to get the custom properties; so special care needs to be given to how the configuration is written.
For example, let’s assume that one of the requirements of your is logging three custom properties: the SessionID {asp.net SessionID}, the raw request’s URL, and an application name. Putting these three variables in a custom object is a good idea (CustomLogProperties in sample). Every time we need to log an event with then create an instance of CustomLogProperites and pass to our logger who takes care of creating a LoggingEvent populated with the custom properties.
Private Sub SetCustomLogProperties(ByVal loggingEvent As log4net.Core.LoggingEvent, ByVal customLogObject As CustomLogProperties)
        If customLogObject Is Nothing OrElse loggingEvent Is Nothing Then
            Return
        End If
        loggingEvent.Properties(CustomFileLogger.ApplicationNameKey) = customLogObject.ApplicationName
        loggingEvent.Properties(CustomFileLogger.RequestKey) = customLogObject.RequestPath
        loggingEvent.Properties(CustomFileLogger.ASPSesssionIDKey) = customLogObject.SessionID
    End Sub
    Private Function GetLoggingEvent(ByVal source As Type, ByVal logger As log4net.ILog, ByVal message As String, ByVal exception As Exception _
                                     , ByVal level As log4net.Core.Level, ByVal customLogObject As Object) As log4net.Core.LoggingEvent
        If source Is Nothing OrElse logger Is Nothing Then
            Return Nothing
        End If
        Dim loggingEvent As New log4net.Core.LoggingEvent(source, logger.Logger.Repository, logger.Logger.Name, level, message, exception)
        SetCustomLogProperties(loggingEvent, customLogObject)
        Return loggingEvent
    End Function
    Public Sub Debug(ByVal source As Type, ByVal message As String, ByVal exception As Exception, _
                     ByVal customLogObject As CustomLogProperties) Implements ICustomLog.Debug
        Dim logger As log4net.ILog = GetLogger(source)
        Dim loggingEvent = GetLoggingEvent(source, logger, message, exception, log4net.Core.Level.Debug, customLogObject)
        If loggingEvent IsNot Nothing Then
            logger.Debug(message)
        End If
    End Sub
Here is the relevant portion of the log configuration file which will instruct the log4net library on how to write the custom properties
<layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date %level %thread %logger - %message %exception [%property{ApplicationName}]
                         [%property{RequestPath}] [%property{SessionID}] %newline" />
    </layout>
Notice the use of %property{property_name} syntax.
Code Listings
Configuration 

    
 <?xml version="1.0" encoding="utf-8" ?>
<log4net>
  <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
    <file value="myLog.log" />
    <appendToFile value="true" />
    <maximumFileSize value="100KB" />
    <maxSizeRollBackups value="2" />

    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date %level %thread %logger - %message %exception [%property{ApplicationName}]
                         [%property{RequestPath}] [%property{SessionID}] %newline" />
    </layout>
  </appender>

  <root>
    <!--<level value="DEBUG" />-->
    <appender-ref ref="RollingFile" />
  </root>
</log4net> 



Sample Code

 

Partial Public Class _Default
    Inherits System.Web.UI.Page
    Private logger As ICustomLog = CustomFileLogger.GetInstance()
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        'log4net.LogManager.GetLogger(Me.GetType().Name).Info(Me.Request.Path + " visited.")
        logger.Info(Me.GetType(), "Page visitied", Nothing, New CustomLogProperties() With {.ApplicationName = "MyApp", .RequestPath = Request.RawUrl, .SessionID = Me.Session.SessionID})
        CauseAndLogException()
    End Sub
    Private Sub CauseAndLogException()
        Dim str = "4/31/2012"
        Try
            DateTime.Parse(str)
        Catch ex As Exception
            logger.Error(Me.GetType(), "An error occurred in " + System.Reflection.MethodBase.GetCurrentMethod().Name, ex, New CustomLogProperties With _
                         {.ApplicationName = "MyApp", .RequestPath = Request.RawUrl, .SessionID = Me.Session.SessionID})
        End Try
    End Sub
End Class

Public Interface ICustomLog
    Sub Debug(ByVal source As Type, ByVal message As String, ByVal exception As Exception, ByVal customObject As CustomLogProperties)
    Sub Info(ByVal source As Type, ByVal message As String, ByVal exception As Exception, ByVal customObject As CustomLogProperties)
    Sub Warn(ByVal source As Type, ByVal message As String, ByVal exception As Exception, ByVal customObject As CustomLogProperties)
    Sub [Error](ByVal source As Type, ByVal message As String, ByVal exception As Exception, ByVal customObject As CustomLogProperties)
    Sub Fatal(ByVal source As Type, ByVal message As String, ByVal exception As Exception, ByVal customObject As CustomLogProperties)
End Interface
Public Class CustomFileLogger
    Implements ICustomLog
    Private Shared _loggers As Dictionary(Of Type, log4net.ILog) = New Dictionary(Of Type, log4net.ILog)
    Private Shared _lock = New Object()
    Private Shared _instance As ICustomLog = Nothing
    Private Sub New()
    End Sub
    Public Shared Function GetInstance() As ICustomLog
        If _instance Is Nothing Then
            _instance = New CustomFileLogger()
        End If
        Return _instance
    End Function
    Private Function GetLogger(ByVal source As Type) As log4net.ILog
        SyncLock _lock
            If CustomFileLogger._loggers.ContainsKey(source) Then
                Return CustomFileLogger._loggers(source)
            Else
                Dim logger As log4net.ILog = log4net.LogManager.GetLogger(source)
                CustomFileLogger._loggers.Add(source, logger)
                Return logger
            End If
        End SyncLock
    End Function
    Private Sub SetCustomLogProperties(ByVal loggingEvent As log4net.Core.LoggingEvent, ByVal customLogObject As CustomLogProperties)
        If customLogObject Is Nothing OrElse loggingEvent Is Nothing Then
            Return
        End If
        loggingEvent.Properties(CustomFileLogger.ApplicationNameKey) = customLogObject.ApplicationName
        loggingEvent.Properties(CustomFileLogger.RequestKey) = customLogObject.RequestPath
        loggingEvent.Properties(CustomFileLogger.ASPSesssionIDKey) = customLogObject.SessionID
    End Sub
    Private Function GetLoggingEvent(ByVal source As Type, ByVal logger As log4net.ILog, ByVal message As String, ByVal exception As Exception _
                                     , ByVal level As log4net.Core.Level, ByVal customLogObject As Object) As log4net.Core.LoggingEvent
        If source Is Nothing OrElse logger Is Nothing Then
            Return Nothing
        End If
        Dim loggingEvent As New log4net.Core.LoggingEvent(source, logger.Logger.Repository, logger.Logger.Name, level, message, exception)
        SetCustomLogProperties(loggingEvent, customLogObject)
        Return loggingEvent
    End Function
    Public Sub Debug(ByVal source As Type, ByVal message As String, ByVal exception As Exception, _
                     ByVal customLogObject As CustomLogProperties) Implements ICustomLog.Debug
        Dim logger As log4net.ILog = GetLogger(source)
        Dim loggingEvent = GetLoggingEvent(source, logger, message, exception, log4net.Core.Level.Debug, customLogObject)
        If loggingEvent IsNot Nothing Then
            logger.Debug(message)
        End If
    End Sub
    Public Sub Info(ByVal source As Type, ByVal message As String, ByVal exception As Exception, ByVal customLogObject As CustomLogProperties) Implements ICustomLog.Info
        Dim logger As log4net.ILog = GetLogger(source)
        Dim loggingEvent = GetLoggingEvent(source, logger, message, exception, log4net.Core.Level.Info, customLogObject)
        If loggingEvent IsNot Nothing Then
            logger.Logger.Log(loggingEvent)
        End If
    End Sub
    Public Sub Warn(ByVal source As Type, ByVal message As String, ByVal exception As Exception, ByVal customLogObject As CustomLogProperties) Implements ICustomLog.Warn
        Dim logger As log4net.ILog = GetLogger(source)
        Dim loggingEvent = GetLoggingEvent(source, logger, message, exception, log4net.Core.Level.Warn, customLogObject)
        If loggingEvent IsNot Nothing Then
            logger.Logger.Log(loggingEvent)
        End If
    End Sub
    Public Sub [Error](ByVal source As Type, ByVal message As String, ByVal exception As Exception, ByVal customLogObject As CustomLogProperties) Implements ICustomLog.Error
        Dim logger As log4net.ILog = GetLogger(source)
        Dim loggingEvent = GetLoggingEvent(source, logger, message, exception, log4net.Core.Level.Error, customLogObject)
        If loggingEvent IsNot Nothing Then
            logger.Logger.Log(loggingEvent)
        End If
    End Sub
    Public Sub Fatal(ByVal source As Type, ByVal message As String, ByVal exception As Exception, ByVal customLogObject As CustomLogProperties) Implements ICustomLog.Fatal
        Dim logger As log4net.ILog = GetLogger(source)
        Dim loggingEvent = GetLoggingEvent(source, logger, message, exception, log4net.Core.Level.Fatal, customLogObject)
        If loggingEvent IsNot Nothing Then
            logger.Logger.Log(loggingEvent)
        End If
    End Sub
    Private Shared Sub FlushLog()
        For Each log In _loggers
            Dim rep As log4net.Repository.ILoggerRepository
            rep = log.Value
            For Each appender As log4net.Appender.BufferingAppenderSkeleton In rep.GetAppenders()
                appender.Flush()
            Next
        Next
    End Sub
    Private Shared ReadOnly ApplicationNameKey As String = "ApplicationName"
    Private Shared ReadOnly RequestKey As String = "RequestPath"
    Private Shared ReadOnly ASPSesssionIDKey As String = "SessionID"
End Class
Public Class CustomLogProperties
    Public ApplicationName As String
    Public RequestPath As String
    Public SessionID As String
End Class

Useful Links:
http://logging.apache.org/log4net/
http://haacked.com/archive/2006/09/27/Log4Net_Troubleshooting.aspx

Monday, January 2, 2012

Finland Education System

Here http://www.theatlantic.com/national/archive/2011/12/what-americans-keep-ignoring-about-finlands-school-success/250564/#.Tv4NA-e7HkY.mailto

The article discusses that the main reason that led the Finnland education system reform was the inequality which was present before at some point of time before the reform itself took place. Therefore, the reform sought to achieve equality across the education system (pre-K to University). There are no private schools. Every student has access to free public education + what comes with it (health care etc.)

Since the 1980s, the main driver of Finnish education policy has been the idea that every child should have exactly the same opportunity to learn, regardless of family background, income, or geographic location. Education has been seen first and foremost not as a way to produce star performers, but as an instrument to even out social inequality.
The article highlights that co-operation is the norm the Finnish education system and that "nothing makes Finn more uncomfortable" than the idea of competition in the context of education.

The article also mentions the high expectations and equally high rewards of educators in Finland:

For Sahlberg what matters is that in Finland all teachers and administrators are given prestige, decent pay, and a lot of responsibility. A master's degree is required to enter the profession, and teacher training programs are among the most selective professional schools in the country. If a teacher is bad, it is the principal's responsibility to notice and deal with it.
Overall, a very interesting read.