Friday, December 12, 2008

Logging to Database With Enterprise Library Part IV - Tieing it all together

In my last post we created all the plumbing that we needed to configure our logger. The final step is to create the actual logger. As a side note I want to say that tried to use TDD development for this piece; however, I have learned that TDD is not the greatest choice when your building plugins. I might elaborate on this in the future but anyways.

To create a custom trace listner for the Enterprise Library you need to derive from CustomTraceListener. You will then need to implement the TraceData function.

    [ConfigurationElementType(typeof(CustomTraceListenerData))]

    public class DBAuditLoggerTraceListener :

        Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.CustomTraceListener

    {

 

        public override void Write(string message)

        {

            throw new NotImplementedException("This method is not supported");

        }

 

        public override void WriteLine(string message)

        {

            throw new NotImplementedException("This method is not supported");

        }

 

        public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data)

        {

 

            AuditLogEntry ale = data as AuditLogEntry;

            if (ale == null)

            {

                //Not an audit log entry

                return;

            }

            IAuditLoggerExpressionGroup logGroup;

            if (!AuditLoggerExpressionCache.Instance.TryGetValue(ale.AuditCategory, out logGroup))

            {

                //Category not registered

                return;

            }

 

            using (StoredProcedure sp = new StoredProcedure(logGroup.Procedure))

            {

                foreach (string key in logGroup.Keys)

                {

                    sp.AddParameter(key, logGroup.GetValue(key, ale));

                }

 

                sp.Execute();

            }

 

 

        }

 



A couple of things to note, The Stored Procedure class is my own class which I am unable to share; however, all it does is wrap up all the ADO.Net Goodness. It also handles my connection strings which is why I am not passing the connection string in. You should be able to quickly whip up your own ADO.Net code. If you run into issues let me know and I will be glad to help out.

Basically all we are doing is making sure we have an AuditLogEntry object, then we check if we have created an ExpressionGroup for this AuditCategory. If we have we simply loop through each of the keys in the ExpressionGroup, calling the GetValue method.

GetValue was needed to ensure that this class didn't have to know about the type parameter in the Expression Group. I'm hopping C#4 with co/contra variance will remove this requirement. Finally we execute the stored procedure.

The next step is to configure this. If your using an ASP.Net app I'd recommend that you configure your expression Groups in the Global.asax. Also remember to call the Cache() method. If you forget this you will not save the expression group you have created.

The final step it to add your logger to the EntLib configuration for example:

<loggingConfiguration name="Logging Application Block" tracingEnabled="true" defaultCategory="Error" logWarningsWhenNoCategoriesMatch="true">

    <listeners>

        <add  listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.CustomTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging,  Version=3.1.0.0"

              traceOutputOptions="None" type="DBAuditLoggerTraceListener, YourAssembly" name="AuditLogger" initializeData="" formatter="Text Formatter"/>

    </listeners>

    <formatters>

        <add template="Timestamp: {timestamp}&#xA;"

            type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging"

            name="Text Formatter"/>

    </formatters>

    <categorySources>

        <add switchValue="All" name="Audit">               

            <listeners>

                <add name="AuditLogger"/>                   

            </listeners>

        </add>   

    </categorySources>

</loggingConfiguration>



I just noticed I had left the text formatter in there which I have not used. I am not sure if this is required or not.

So after all of this what do we have? A logger that will take any AuditLogEntry and execute a stored procedure, with any number of parameters. I hope you find this useful. Please feel free to provide any feedback positive or negative.

Enjoy!

Update

I have extracted the source and posted online. Please note that this is not tested, so if you run into any issues let me know. When I get caught back up with my day job I will try and finish rounding this out.

Let me know if this link doesn't work. First time I've used skydrive so I'm not positive I have it all setup right.

Logging to Database With Enterprise Library Part III - Expression Cache

In my previous post we started to explore a solution for logging any arbitrary data to the database using the Enterprise Library.

Next on our list of things we need to create our Expressions. Not wanting to create the expressions each time we need to log the data, and not wanting to tie our method for extracting data from the log entry to the log entry, I opted to create what I am calling the AuditLoggerExpressionCache or Expression Cache for short. The expression cache uses the singleton pattern to ensure we only have one cache for our process.

The cache doesn't actually store the expressions directly but it stores a group of expressions, keyed off the AuditCategory.

public class AuditLoggerExpressionCache

{

    private Dictionary<string, IAuditLoggerExpressionGroup> _expressionGroups =

        new Dictionary<string, IAuditLoggerExpressionGroup>();

    private AuditLoggerExpressionCache() { }

 

    public void Add(IAuditLoggerExpressionGroup group)

    {

        this._expressionGroups.Add(group.Name, group);

    }

 

    public IAuditLoggerExpressionGroup this[string key]

    {

        get

        {

            return this._expressionGroups[key];

        }

    }

    #region Singleton Pattern

    public static AuditLoggerExpressionCache Instance

    {

        get

        {

            return singleton.Instance;

        }

    }

    private class singleton

    {

        internal static readonly AuditLoggerExpressionCache Instance = new AuditLoggerExpressionCache();

    }

    #endregion

 

    public AuditLoggerExpressionGroup<T> CreateGroup<T>(string category, string connection, string procedure)

    {

        return new AuditLoggerExpressionGroup<T>(category, connection, procedure);

    }

 

    public bool TryGetValue(string category, out IAuditLoggerExpressionGroup logGroup)

    {

        return this._expressionGroups.TryGetValue(category, out logGroup);

    }

}



I have defined an IAuditLoggerExpressionGroup interface which allows us to access the groups without having to know the generic parameter type. I am using the Generics to improve the syntax since you won't have to cast the AuditLogEntry in your lambda.

public interface IAuditLoggerExpressionGroup

{

string Name { get; set; }

string Connection { get; set; }

string Procedure { get; set; }

Delegate this[string key] { get; }

IList<string> Keys { get; }

object GetValue(string key, object param);

}



A couple of key properties. The name here is the audit category, the Connection is intended to be used to store the connection string, the Procedure is the name of the stored procedure to execute. Keys is the keys to the expression dictionary itself. I am using the keys also as the stored procedure parameter names.

Let's look at the ExpressionGroup:

public class AuditLoggerExpressionGroup<T> : IAuditLoggerExpressionGroup

{

 

    private Dictionary<string, Func<T, object>> _expressions =

        new Dictionary<string, Func<T, object>>();

 

    public AuditLoggerExpressionGroup(string name, string connection, string procedure)

    {

        this.Name = name;

        this.Connection = connection;

        this.Procedure = procedure;

    }

 

    #region IAuditLoggerExpressionGroup Members

 

    public string Name { get; set; }

    public string Connection { get; set; }

    public string Procedure { get; set; }

 

    public Func<T, object> this[string key]

    {

        get

        {

            return this._expressions[key];

        }

        set

        {

            this._expressions[key] = value;

        }

    }

    public IList<string> Keys

    {

        get

        {

            return this._expressions.Keys.ToList();

        }

    }

 

    public AuditLoggerExpressionGroup<T> Add(string key, Func<T, object> expression)

    {

        this._expressions.Add(key, expression);

        return this;

    }

 

    public AuditLoggerExpressionGroup<T> Cache()

    {

        Check.Require(!string.IsNullOrEmpty(this.Name), "You cannot cache something without a name");

        AuditLoggerExpressionCache.Instance.Add(this);

        return this;

    }

    public AuditLoggerExpressionGroup<T> Cache(string name)

    {

        this.Name = name;

        return this.Cache();

    }

 

    public object GetValue(string key, object param)

    {

        return this[key]((T)param);

    }

    Delegate IAuditLoggerExpressionGroup.this[string key]

    {

        get

        {

            return this[key] as Delegate;

        }

    }

    #endregion

 

}



One thing to note I am using the Design By Contract class. This is however optional but if your not using it, be sure to go have a look its a great additional to your programming toolbox. The expression group as you see in the Add method takes a key, and a Func. T is your specific AuditLogEntry class, and we are returning an object.

At this point your unit test should work, and the vast majority of the work has been done. The only thing left is to define and configure the actual trace listener. I will cover this in Part IV of this series.

Logging to Database With Enterprise Library Part II

I've been surprised at how much traffic my little insight into the lack of functionality that the out of the box database log listener has in the Enterprise Library. So much that I figured it was time to share my first pass on creating a log listener that can dynamically pull attributes from a LogEntry and call any stored procedure.

To set expectations this is a first pass solution which took me a couple of hours to come up with. It is not complete by any means, and there is plenty of places that it could use work; however, it is 100% functional and solves the problem I was setting out to solve. I appreciate any and all feedback. If you take this code and improve upon it let me know I'd love to know!

I am currently using Enteprise Library 3.x, so this might have changed with their more recent 4.0 release.

When building this I had a critical to make which was how do we configure this? I wanted to be able to specify two values a parameter for the stored procedure, and a property / method to be invoked on the LogEvent object. I could have used reflection, LCG, code dom...there are lots and lots of options; however, I wanted to choose something that would be fast at runtime (Reflection is out), and that would be quick for me to code (LCG and Code DOM are out).

I opted for using Lambda Expression, which are very efficent at runtime, and which I could code to very very quickly. This is one area for improvement, right now the expressions can be defined in a configuration file; however, this is definetly something that is possible, and that I would love to add.

I built this so that defining the properties via configuration are optional. I've been using Fluent nHibernate lately and I've learned to enjoy the refactoring support that exists in defining your configuration in code. So the pieces that we need to implement are:
  1. A dictionary of Expressions that call properties or methods on a LogEntry object
  2. A trace listener that uses the dictionary to construct a stored procedure call
  3. A log entry object that can tie the trace listener to the expressions

So let's get started. First thing I did was created a unit test to see what kind of interface I needed for my Expression dictionary. This looked like :


[TestMethod]

public void InitalizeExpressionCache()

{

    var cache = AuditLoggerExpressionCache.Instance;

    string category = "UnitTest";

    string connection = "[CutterMain]";

    string procedure = "sp_InsertUnitTest";

    cache.CreateGroup<AuditLogEntryUnitTest>(category, connection, procedure)

        .Add("MyProperty", ale => ale.MyProperty)

        .Cache();

 

    AuditLoggerExpressionGroup<AuditLogEntryUnitTest> grp = cache["UnitTest"] as AuditLoggerExpressionGroup<AuditLogEntryUnitTest>;

    AuditLogEntryUnitTest entity = new AuditLogEntryUnitTest();

    Assert.AreEqual(entity.MyProperty, grp["MyProperty"](entity));

}



AuditLogEntryUnitTest is a simple fake class to test the framework. I suppose you could substitute your own Mock using your favorite mocking framework:

public class AuditLogEntryUnitTest : AuditLogEntry

{

    public AuditLogEntryUnitTest()

        : base("Unit test", "UnitTest")

    {

    }

    public string MyProperty { get { return "MyProperty Called"; } }

}



Next we are going to define an AuditLogEntry class. This should be the base class for all of your auditing log entries. This class is defined as:

public class AuditLogEntry : LogEntry

{

    public AuditLogEntry(string auditMsg, string auditCategory)

    {

        //if (MembershipService

        this.Categories.Add("Audit");

        this.Categories.Add(auditCategory);

        this.Message = auditMsg;

        this.AuditCategory = auditCategory;

    }

 

    public string AuditCategory { get; set; }

}



This class adds an AuditCategory property, which is also added to the LogEntries categories so you can do filtering on it. The AuditCategory is important as it is is used to tie our LogEntries to the Expression Dictionary.

The next post in the series will explore the Expression Cache.

Wednesday, December 10, 2008

Microsoft Bizspark

Startups are by the very nature of them cash strapped. I cannot speak for all startups but from my personal experience, we were forced to scrap together to buy the software we needed to start our business. For example, we were using trial versions of visual studio to build our prototype, and when it ran out were able to get a professional license as a door prize. And latter we upgraded to a single MSDN Team Suite DB Edition license.

I've also mumbled to myself that Microsoft should help early stage startups, it trully is in their best interest, since if our company succeddes, we will be buying lots of their products. The MSDN licenses can run anywhere from 2k-5k dollars.

It turns Microsoft has been addressing this need, by essentially giving away their best development tools. The Microsoft Bizspark program gives an unlimited number of MSDN Team Suite licenses for a cost of $100.00 (payable when you exit the program). There are many other benefits in the program, but this one was great. Pitty we can't return our earlier MSDN subscribtion, but this will save us thousands of dollars as we add more developers and grow over the next couple of years.

You can also read more about the program here: http://blogs.msdn.com/somasegar/archive/2008/11/05/bizspark-software-for-startups.aspx

Friday, December 5, 2008

Using Self Signed Certs on Vista

I needed to enable certificates for my WCF service, I first went and added the following behavior to my service:


<behavior name="MyServiceBehavior">
<servicecredentials>
<servicecertificate findvalue="MyLocalHost" x509findtype="FindBySubjectName" storelocation="LocalMachine" storename="My">
</servicecredentials>
</behavior>

Then following the steps here: http://msdn.microsoft.com/en-us/library/ms733813.aspx I created a self signed certificate to add to the root and certificate to use for my service.

I then tried to bring up the services help page and I get this error:

The certificate 'CN=SignedByLocalHost' must have a private key that is capable of key exchange. The process must have access rights for the private key.

Doing some searching I found that you need to use winhttpCertCfg to give permissions to the process account. I also found that this tool is deprecated in Vista. It may or may not work but I wanted to figure out how to get this to work.

The suggested method was to use the MMC snap in to manage Private keys. You need to right click on the certificate and there should be a "Manage Private Keys" option under All Tasks, but it was there for me.

After some more diging I found you need to create the certificate for exchange. The following command worked:

makecert -sk SignedByCA -iv c:\OutCert.pvk -n "CN=MyLocalHost" -ic c:\OutCert.cer -sr LocalMachine -ss My -sky exchange -pe

The thing I left off was -sky exchange

The next error I ran into was:

The X.509 certificate CN=MyLocalHost chain building failed. The certificate that was used has a trust chain that cannot be verified. Replace the certificate or change the certificateValidationMode. The revocation function was unable to check revocation for the certificate.

To resolve this you need to do what it says (of course the trick is finding where to change this setting at). Add the following behavior to your client code



<behaviors>
<endpointBehaviors>
<behavior name="ssl">
<clientCredentials>
<serviceCertificate>
<authentication certificateValidationMode="None"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>

Thursday, November 20, 2008

ASP.Net MVC Hyperlinks and Suboptimal Design

I never thought that after 8 years of professsionally programing I would be stumped at how to create a hyperlink. Well with ASP.Net's MVC framework there are a lot of ways to create links, and I want to share an experience I am having.

I want to create a link to my Product controller, calling a ListProductsByCategory action passing in a single parameter which is the id of the category. This should be a very simple pattern, and while yes I could hardcode the link such as:

<a href="Product/ListProductsByCategory/1">Widgets</a>


However, there should be a better way, and in fact there is. The ViewPage has a property called Html which has helper methods to help rendering a view. One of the methods is ActionLink, which sounds like what we need. So if we look at all the overloads we see two in particular:

  1. string linkText, string actionName, string controllerName, object values, object htmlAttribute
  2. string linkText, string actionName, string controllerName, RouteValueDictionary values, RouteValueDictionary htmlAttributes


Option 2 is fairly self explanatory based on the signature of the API. It looks like it takes a collection of parameters that is probally name value (I've not had the time to dig into what a RouteValueDictionary actually is). The problem I have with this is I really don't want to clutter up my markup with the syntax of building a dictionary. So seeing option 1 I figued I could do:

 <%=Html.ActionLink("Accessories",
"ListProductsByCategory", "Product", 3, null)%>


This resulted in the following html being generated:


<a href="Product/ListProductsByCategory">Accessories</a>


The problem is we have lost the value portion of the url. After reading Oren's post on some of his issues with the API Design I figured this was something more then a simple object that they were expecting but what? The API provides no hint as to what it might be (and the intellisense doesn't have the documentation yet so there were no tooltips).

Firing up google I came accross this post which showed me what I was missing. The object is actually an anonymous type, which surprises me since I had thought you couldn't pass anonymous types around. Well so anyways our code now looks like:


<%=Html.ActionLink("Accessories", "ListProductsByCategory", "Product", new { id = 3 }, null)%>



The only reason I feel this is suboptimal is that the API signature doesn't provide any hint as to what is expected. I prefer an API where I don't have to google to figure out the parameters, and with in most modern development environments this can be accomplished using good names mixed with intellisense. In this case, I wish the intellisense for the parameters would have been available and it could have explained what I needed. But I understand this is a beta version. I wonder why anonymous types don't have a base type other then object, that would have also made this more discoverable.

This works like a charm!

-Josh

S#arp Arch & MSTest

I have just started a new project, and as such I took this chance to further my exploration into alternative models then standard ASP.Net Webforms. I have been curious to learn more about ASP.Net MVC, and I wanted to continue exploring nHibernate.

When I first implemented nHibermate I used a model which was basically based upon Billy McCafferty's work; however, during this I found severe limitations one of which I blogged about here. Billy has been hard at work at developing a new set of patterns which are encapsulated in an architecure called S#arp.

One small glitch I ran into related to my use of MSTest. Billy has created a base class that all Respository test classes can inherit from. This class will setup and tear down nHibernate session and roll back any transactions which should help keep your database at a known state.

However, this class assumes the use of nUnit. Which when you try and use this from within MSTest it causes a null reference exception when you try and access the repository. If your like me and want to ue MSTest a real simple solution is this:

  1. Inherit from the RepositoryUnitTestsBase class.
  2. Explitly call the Setup and Tear down methods

So your class should basically look like:


    [TestClass]
    public class ProductRepositoryTest : RepositoryUnitTestsBase
    {
        [TestInitialize()]
        public void MyTestInitialize()
        {
            this.SetUp();
        }
 
        [TestCleanup()]
        public void MyTestCleanup()
        {
            this.TearDown();
        }
    }


I'd love to see these methods moved out into a seperate utility type class.

Enjoy
-Josh

Friday, November 14, 2008

Wordle

I ran into a site that is a lot of fun to play with. Wordle is a small java applet which will build one of those word clouds based on text you enter, or given a URL it will build the cloud based on the page. You can check out my cloud here



They also give you html you can use to link the image right into your blog. Which I have done with this post:




If you've had success with this service, or know of any other like it leave a comment. Thanks!

The joy in the smallest of things, that we might take for granted

Our production server, has been a VM using VMWare sitting on some type of non-windows platform. This server wasn't gen'ed by me and it has historically caused me pain (.Net was installed before IIS so I had to manually register everything for example). I've been axiously waiting for us to get a second box, ramped up, and now after months of waiting (And yes if my boss read this I admit I was part of the bottle neck for the last two months). We have a new server, and I was able to shut down the old server.

What does this have to do with the smallest of things that might take for granted? Well in the last three months, I have caused two different outages of our application on two occasions for roughly 10 minutes at a time. What was I doing you might ask? To take down a server, I must have done serious like reboot, or killed IIS, maybee I messed with the configuration files?

Nope none of that. All I did was empty the stinking recycle bin, and neither of those times did I ever let it finish it took me 10 minutes to get the status window focused so I could click the cancel button.

Now if you'll excuse me I'm going to create a couple thousand files, so I can delete them and empty the recycle bin....Ahhh the small things in life!

- Josh

Wednesday, October 29, 2008

New version of Goto Meeting

I've been using Goto Meeting off an on for a couple of years now to do virtual meetings. I have to say I'm impressed with one feature in particular.

In the latest version their audio-conference is smart enough to detect when I am talking through the phone, and it updates the UI telling all the participants that I am talking. I find this simply amazing, and maybee its because I am tired, sick, and have been sitting here for 8 hours straight looking at code, but I really wonder what it takes to do that.

Anyways its a great inexpensive tool for hosting virtual meetings. Go check it out.

Monday, October 27, 2008

nHibernate Transaction & Session Mgmt

I've been using nHibernate for a couple of months now, and have been using Billy McCafferty's basic architecture with some of my own added spin. Today I noticed a strange behavior in nHibernate 2.0 which I've not fully explained or explored so bare with me.

I have an Organization object, and there's a screen where a user can modify the properties and save the object back to the database. I wanted to add additional error handling around the app to make it friendlier, so I removed one of my safeguards that let me generate an error (passing in a string larger then what the DB is configured for), and ran through my test. Essentially the page method doing the save looked like:

 protected void saveOrgInfo_Click(object sender, EventArgs e)
    {
        try
        {
            DoSave();
            this.saveStatus.Text = "Your changes have been saved.";
            this.saveStatus.Visible = true;
            this.saveStatus.CssClass = "successText";
        }
        catch (Exception ex)
        {
            CutterLogEntry.LogError("Error saving OrgInfo", ex);
 
            this.saveStatus.Text = "There was an error saving your changes. Please try again.";
            this.saveStatus.Visible = true;
            this.saveStatus.CssClass = "warnText";
        }
    }
 
    private void DoSave()
    {
        NHibernateSessionManager.Instance.BeginTransactionOn();
        MembershipService memService = new MembershipService();
        this.orgInfo.UpdateOrganizationInfo(Util.CurrentUser.Organization);
        memService.SaveOrganization(Util.CurrentUser.Organization);
        NHibernateSessionManager.Instance.CommitTransactionOn();
    }


One of my modifications was to add overloads to his methods which don't accept a path to the config file, and when this is used it defaults to the Web.Config / App.Config file.

What I found interesting was that I was being redirected to an error page, when based on this code my catch should have handled this. The call stack in the error page indicated that the error was originating in my httpModule which tries to close any open session.

When we tried to call Close on the session the nHibernateSessionManager also calls a flush() which will cause nHibernate to try and save the Organization entity again. The interesting thing here is if we look at the logic in the Commit method, when it fails the SessionManager tries to rollback the transaction:


        public void CommitTransactionOn(string sessionFactoryConfigPath) {
            ITransaction transaction = (ITransaction)ContextTransactions[sessionFactoryConfigPath];
 
            try {
                if (HasOpenTransactionOn(sessionFactoryConfigPath)) {
                    transaction.Commit();
                    ContextTransactions.Remove(sessionFactoryConfigPath);
                }
            }
            catch (HibernateException) {
                RollbackTransactionOn(sessionFactoryConfigPath);
                throw;
            }
        }



If we follow the source the Rollback will call the rollback transaction and then call the CloseSessionOn() method. The CloseSessionOn() method will attempt to flush and then close the session. The call to flush will generate an exception here. Because of this exception, the close method is never called.

So when the HttpModule kicks off it sees there is an active session, and then trying to close it calls a flush which generates the exception again. All in all this one exception was thrown three times so far.

I find it strange that nHibernate would try and save an object that was "Saved" within a transactional context. I would imagine that a Rollback should clear out all dirty entities; however, it doesn't. The quick fix is as I said to modify the Rollback method so that it closes (but not flush).

Enjoy

Josh

Tuesday, October 21, 2008

TypeLibBuilder.exe Crashes & DigitalPersona Software Update III

I have been informed that Digital Persona will be releasing a patch which addresses the issue with Visual Studio 2008's TypelibBuilder which is responsible for the JavaScript Intellisense feature. See these posts for more information:

I do not know when or where the patch will be made available, but as soon as I know more, I will update this blog entry.

I want to thank the Microsoft & Digital Persona development teams for working together, to get a resolution to this issue. While this issue didn't prevent someone from doing their work, it did require that they choose btw two great features (Java Script Intellisense, or using BioMetrics to save typing and remembering all those passwords).

Enjoy

-Josh

Friday, October 17, 2008

Firefox & GoDaddy SSL Certs

This is primarly a note to self:

When installing a GoDaddy SSL Certificate make sure you install the intermediaries from: https://certs.godaddy.com/Repository.go. the one you need is: Go Daddy PKCS7 Certificate Intermediates Bundle (for Windows IIS). If your not using IIS you will need to find the right file on that site.

To install follow these steps:
  • Open MMC and add Certification Store for the local computer account.
  • Go to the Intermediate Certs => Certificates folder, right click on it and select import.
  • Browse to the intermediary file and select it, and complete the wizard

Enjoy

Josh

Unrelated Google Add Words Adds

So I've been playing around with Google Addwords on my blog as a way to understand how they work (and in the hopes I might get enough clicks to help fund my kids Holiday seasons which in my house is crazy with Hanukah, Christmas, My oldest's birthday and my wife's birthday all falling within a two week period).

At first I figured the content wasn't focused on the things I blog about because it was so new, and google hadn't scanned enough content. But after 9 months now I figure the ads should become more appropiate. Yet today I am always seeing ads for some type of Surgery, or today was for a Cookie School of some sort (Which was right next to an ASP.Net School).

Anyone reading this want to provide some insight into what I am doing wrong?

Updating LastActivityDate in ASP.Net Membership Issue

So I've just finished rolling out the latest version of my application, which included a huge overhaul of the membership model. Essentially I replaced the entire Asp.Net Profile provider, with my own variation which fits better for my domain (Organization having many users).

I deploy out my site, and everything is running good for a couple of days, then we start to have issues (Which is a whole other story I will spare you all from). So before taking the site down I wanted to see who was using the site. I went over to my trusty administration interface and brought up the user report and what did I see?





UserLast Activity Last Login
JoeSmith10/17/08 11:00 AM10/17/08 11:00 AM
BobSmith10/17/08 11:05 AM10/17/08 11:05 AM


If you can't spot it the issue was all the users last activity date was the same as the last login. Now the kicker is that I have a client side timer invoking a web service every couple of minutes. This service makes a call to System.Web.Security.Membership.GetUser(). If you look up the msdn information you will see that GetUser() is supposed to update the LastActivityDate.

Digging around in the stored procedure [dbo].[aspnet_Membership_GetUserByName] you should see the following:

UPDATE dbo.aspnet_Users
SET LastActivityDate = @CurrentTimeUtc
WHERE @UserId=UserId



You can resolve this by modifying this to:

UPDATE dbo.aspnet_Users
SET LastActivityDate = @CurrentTimeUtc
WHERE LOWER(@UserName) = LoweredUserName


Before you purists jump down my back yes I left off ApplicationName because I only have one application, and our business currently mandates that all users in all of our applications share the same login and personalization. If you need to support multiple applications you can get the ApplicationId from the Application table. If you really need the sql drop me a comment and I will pull it out.

On a side note once the Connect site came back today I was able to confirm this is an old issue

Thursday, October 16, 2008

TypeLibBuilder.exe Crashes & DigitalPersona Software

Updated:

See the update at: http://jberke.blogspot.com/2008/10/typelibbuilderexe-crashes_21.html
=================


Hello,

This is a follow up to an earlier blog post about TypeLibBuilder.exe crashing which was caused by Digital Personas Finger Print Reader Software included in many laptops like my HP DV 9700 here.

I have had a short discussion with one of the Web Dev Tools managers via this forum post: http://forums.asp.net/p/1283140/2685200.aspx#2685200 It doesn't sound like Microsoft has any plans to publish a fix for this issue as they insist that the issue is within Digital Persona's software. I am unable to weigh in on this as I really don't know what each of the two conflicting components are doing. While I dissagree with Microsoft's position, I can understand where they are coming from.

I have also had communications with Kirill Lozin Director of Software Development for Digital Persona. When I originally discovered this issue the best I was able to do was get in touch with DP's sales team; however, since this was considered a free version of software I was unable to get further. Thankfully the manager from Microsoft provided me with Kirill's contact information who has provided the following information.

Digital Persona plans to include a resolution for this issue in the upcoming DigitalPersona Personal v. 4.0 release. This release is planned for October 31, 2008; however, this is a tenative date.

This is great news; however there is a catch. At this time Kirill Lozin is not aware if this release will be made available to those of us who recieved the free version of Digital Persona (I contest that this wasn't free since it was bundled with Vista but anyways...). Keep in mind he is not indicating that it won't be available or that will be available just that he doesn't know what the plans are.

He has promissed to push the patch ideas as strongly as possible; however, there are some complications which has stopped this idea already due to all the notebook manufacturers requiring being required to approve any patch.

I will update my blog as new information is made available.

Thanks,

Josh

Monday, October 13, 2008

Limiting Concurent Users in ASP.Net Sites

I've recently finished implementing a membership model enhancement for my current companies application. This model has a notion of an organization, which then has one or more user accounts. This allows users at a single organization to share data between their accounts.

With this enhancement, a business requirement came in to prevent multiple physical users from sharing a single user account. When I sat down to solve this problem, the first thing I did was fire up google and see what other people have done. All of the recommendations I found was focused on preventing a user from logging to the site and worked like this:
  1. User tries to login, site checks for some identifying piece of information from the client like a guid stored in a cookie.
  2. If there is no cookie then create one.
  3. The site then takes the cookie and looks up in a table (in memory or DB for example) and checks if this cookie is the same one for this user.
  4. If there is no entry in the table or the cookie is the same the user is able to login.
  5. If the cookie doesn't match the user is locked out.

This is an ok algorithm, but its main weakness is that it assumes that we know when a user logs off, which is impossible in an ASP.Net page. One idea and I forgot where I saw this was to use ASP.Net cache to store this entry, we can then set it to auto expire so that if a user gets locked out it would only be for a couple of minutes.

When I thought about this model, the biggest thing I didn't like is that it punishes the user, if for example his browser crashes. It would be even worse if it crashes because of my site and then I prevent him from logging in for five minutes.

I wanted to come up with a solution which works like many of the IM's out there. I wanted a last one in wins model. So how did I achieve this within Asp.Net?

  1. User logs in, and a new Guid is generated, and stored in a non-persistent cookie, and its stored in HttpContext.Current.Cache, using the user's login as a key.
  2. A client side timer is initialized in the main page of the application. This works nicely for us since the user never navigates away from this page currently; however, this same approach could be adapted to other navigation structures.
  3. This timer kicks of a call to a very simple Ajax enabled WCF service.
  4. The service checks the guid stored in the user's cookie.
  5. The services looks into cache for the guid, if no guid is found the value in the cookie is stored. This handles the case of the cache being flushed out.
  6. If the cookie doesn't match the cached item, then a false value is returned to the client.
  7. If the cookie matches the value in the cache a true value is returned.
  8. The client then navigates to an error page if the value is true, it also tracks any dialogs that were opened and navigates them as well.

This algorithm allows us to enforce the requirement to limit concurrent users, while still preventing frustration of a user being locked out because their browser crashed.

Enjoy

- Josh

ps. If I ever get around to building any diagrams I will update this.

Response.Redirect() & ASP.Net Pipeline

I've just finished debugging a fun a bug related my nHibernate code. Essentially I was getting an error that indicated that I was trying to associate a collection with more then one active nHibernate session.

This made no sense within my architechure. I am using a static session manager which essentially creates and caches nHibernate sessions on demand. It stores the session within HttpContext or within CallContext depending upon the environment its loaded in. I then implemented a very simple HttpModule which would flush and close the session after the request is done processing. I was relying upon the PostRequestHandlerExecute event to do this cleanup.

What I discovered is that in one of my pages which had a Response.Redirect() in it, this event is never actually being called. The solution is simple. Use the EndRequest event instead.

One concern I have within the context of my nHibernate architecure is the idea of doing work on the database after the page has finished executing for the user. What happens if an error occurs? I might have shown the user that everything was ok but in fact it wasn't. I'd be curious if anyone has any advice about this one?

Enjoy
-Josh

Wednesday, October 1, 2008

Preparing for IE8

My boss recently installed IE8 Beta 2 just to see what would happen. Of course he decided to go and navigate to our application which resulted in the usual phone call we all dread:

Boss: So Josh I just installed IE8.
Me: Huh huh, and how'd it go?
Boss: Our site looks like crap...

And I am sure you can imagine the rest of the conversation. Our site is optimized for IE7 standards mode, which isn't exactly compatible with IE8 standards mode.

There are a couple of ways we can resolve this. We can invest the time to bring our site up to IE8 standards mode compliance (and in the process hopefully add support for the other browsers which we don't support); however, this takes time which costs money which new startup companies don't always have the luxury of.

Another solution is for the site to lock in to a particular rendering engine. This is a brilliant addition to the architechure of IE, and I hope other browsers follow suit. Its the same concept of being able to lock in your client application to a particular version of .net.

I won't regurgitate how to do this. A really good article is available here.

Tuesday, September 23, 2008

Logging to the database with Enterprise Library

Update:

I have since started my own implementation which is describered in the following articles:

================================

So I've been using the Enterprise Library's logging block since v1; however, I've always logged to mostly unstructured or semi-structured locations such as email, files or the event log. I've had a lot of success using the block for logging exception messages or basic application events.

In all the apps I've ever written I've always had a need for a more robust strongly structured data store to facilitate reporting, and I've always resorted to rolling my own. Over the years the implementations have varried from very narrowly focused systems that support a single subsystem to more generic mechanism that support a various paradigm. For example logging of the messages within an SOA environment.

  • Incoming Message
  • Outgoing message to the next service
  • Reponse from that service
  • Response to the original request.

When ever its time to implement these systems, our team would always debate if we could leverage the Enterprise Library logging block; however, we've found that it was always easier to just roll our own quick dirty logger.

Today I had to ask this question again, only this time I am a team of one so I only had myself to argue with. I want to store an audit trail when a user logs into my web application, and collect all the fun stats such as his browser. (I know I could look at the iis logs but that won't let me profile which browsers have access to certain features, without having to figure out which urls if any compose a specific feature...this can be a whole other post so I will leave it at this).

The enterprise library does support a datbase trace listener out of the bat; however, it is seriously flawed. The listener can only log to a very specifc table structure. There is no way to say, I want to add this piece of information such as the IP Address of the client to the table as a seperate field.

The table does a text field called FormattedMessage which will use an Formatter that is asociated with the listener to generate a message. So while it is possible to get my IP Address in there, it forces to fall back onto to a non-relational model such as XML. While I love this flexibility, I've seen many DBA pulling their hair out at 3:00 am when they need to pull and aggregate data from a XML blob. Since this is a text field and not the Xml Data Type, I can't really enforce a schema.

So what is a poor developer to do? Well I don't have a solution implemented yet...But I plan on creating my own database trace listener that will let you specify the parameters and how to pull the values from the LogEntry object dynamically.

If I make any progress I'll add a new post. If anyone is aware of any solutions out there let me know.

Thanks,

Josh

Saturday, September 6, 2008

Setting up a printer on Windows Home Server

I recently won an HP Home Server (I actually got it about a month ago and decided to break it out of the box today). Its amazing how much life has changed for me in 10 years with a wife and three kids. 10 years ago that server would have been unpacked and up and running within an hour of getting it.

Anyways so far I am fairly happy with how easy it has been to setup the media server. I've just finished adding my Lexmark 5495 to the server, it took me longer to find the right drivers then it did to actually install them.

My only issue with the process is that you have to use remote desktop and login to the server. The help documentation for Home Server actually advises that you do not do this. Sharing resources like a printer seems like such a common task that it would have been nice for them to find a way to integrate into the Home Server Console.

To install a printer you can simply hook the printer into the USB or Parralel port, and then one of two things will happen. Either the server will detect the printer and install the printer or you will have to do this manually. You can check if the printer was installed by going to the shared folders and you should see the printer, if you do not then you will need to do it manually.

To do this open up remote desktop and connect to the server. Then you will install the drivers just as you would on any other computer.

Once the printer is installed you can connect to it by going to \\YourServerName\Printers You will also see the printer at \\YourServerName\NameOfYourPrinter. When you right click on the printer you can select connect and it should install the drivers for you.

Enjoy
Josh

Wednesday, August 27, 2008

Bashing and Rants

Here's a good example of the problem with blogging technology. You give anyone the ability to instantly publish and your going end up with some dribble and rants.

This article is nothing but bashing of MS, and provides no substantiation of any of the claims the author makes. Give examples of good projects that have been squashed due to the giant beast gobbling up the developers and forcing them to stop working on a project.

As Oren Eini put it so nicely
Who exactly said that I owe something to anybody? Who exactly said that any of the guys who went to work for Microsoft (many of whom I consider friends) owe you something.


How dare anyone have the audacity to claim an evil doing that a developer of a free tool abandoned the project.

I guess that's the problem of free space and cheap publishing technology but now my rant about the ranters is over.

Enjoy!
Josh

Sunday, August 24, 2008

Unit Tests & Expected Exceptions

Good unit test coverage should include tests that cover the normal use cases in your code, and tests that validate any bounds are being checked. What does this mean? Take for example the following function.


public File OpenFile(string filePath)

{

Check.Require(!string.IsNullOrEmpty(filePath),"Path cannot be null or empty");

Check.Require(File.Exists(filePath), "Path must exist");

...

}




A good unit test suite will ensure that the code handles the exception cases, when the codes pre & post conditions are not met. When writting these tests you will need to watch for exceptions. One quick implementation of this is:

try

{

FileInfo file = OpenFile(null);

}

catch (PreconditionException ex){}

catch (Exception badEx)

{

Assert.Fail();

}



While this works it suffers from a critical problem that how do I know which exception we were expecting to get? Unless this is documented, I can't be certain of the original test writters intentions.

Many of the unit testing frameworks provide a solution to this with an ExpectedException (or some variant there of) attribute which can be placed on a test method. This attribute typically takes a type of exception and optionally a message that should be the message of the exception.

This is definetly better and results in a simple test in the MS Test framework such as the following:


[TestMethod]

[ExpectedException(typeof(PreconditionException))]

public void OpenFile_NullPathTest()

{

FileInfo file = OpenFile(null);

}



This works fine in this simple case, but what if we have a more complex test, or we are doign an integration test and testing lots of components. If any component throws the exception then your test will still pass.

A better way would let us both clearly express the intent of the test, and to narrow down a specific line or set of lines that should generate the exception.

In C# 3.0 we can leverage delgates and extension methods to come up with a simple way that achieves these goals. Our test method now looks like:



[TestMethod]

public void OpenFile_NullPathTest()

{

Action action=delegate{ OpenFile(null); };

action.ExpectedException(typeof(PreconditionException));

}




This test clearly states that the OpenFile(null) call will result in a PreconditionException, and if there is other stuff occuring within the test, we don't have to worry about the test passing when it should have passed.

The ExpectedException method is an extension method on an Action Delegate. Action is a general delegate that takes no arguments and returns a void. To use this you need to add the following method to a static class, and make sure that the class is within a referenced name space (using in C# or imports in vb).



public static void ExpectedException(this Action action, Type expectedException)

{

try

{

action();

Assert.Fail("Expected exception did not occur");

}

catch (Exception ex)

{

Assert.AreEqual(expectedException, ex.GetType(), string.Format("Expected exception of type {0} but recieved exception of {1}", expectedException.Name, ex.GetType().Name));

}

}



This method could be enhanced to allow checking that the right exception is thrown but that the message is what you expect; however, I'll leave that as an exercise for you.

If your not a big fan of extension methods you could do this using a delegate or even nicer with a lamba such as:
TestHelper.ExpectedException(() => OpenFile(null),typeof(PreconditionException));

Enjoy!

Josh

Edited: 11-17-2008 Added an Assert.Fail() after we call the action delegate in our test helper.

Wednesday, August 20, 2008

Overidding a javascript method

As I'm forced to spend more time doing client web development, I'm finding javascript to be an interesting language to work. Recently I've discovered a fun way to override a method on a javascript object that I would like to share.

Let's take the following example:

function apple(color)


{


this._color=color;


}



apple.prototype.AlertColor=function()


{


alert(this._color);


}



var myApp=new apple("red");


myApp.AlertColor();




When you run this inside a web page you'll get an alert box with the color red. Now let's pretend that our apple is an external script, which is used in many web pages; however, in one specific page we need to change the functionality of the AlertColor method. How do we do this?


apple.prototype.AlertColor=function()


{


alert("blue");


}



var myApp=new apple("red");


myApp.AlertColor();




What we are doing here is replacing the definition of AlertColor on all instances of apple with our new function. Running this script will give you an alert of blue. Let us go one step further and pretend that we want to wrap custom functionality around the AlertColor function.


apple.prototype.Original_AlertColor=apple.prototype.AlertColor;



apple.prototype.AlertColor=function()


{


alert("You are asking about the color well I am...");


this.Original_AlertColor();


}



var myApp=new apple("red");


myApp.AlertColor();




Here you will get two alert boxes. What we have essentially done is add a new function called Orginal_AlertColor and we set to the orginal AlertColor function. Then with our new function we call the original function.

Now that hopefully we understand the basic how to, what can I do with this? Here are some examples I've found in the wild:
  • TextBoxWatermark Extender in Ajax Control toolkit uses this approach to replace the default ASP.Net function for submitting a form. They use this to blank out the watermarked text before posting back to the server.
  • Component Art recommends using this to replace the standard window.alert() method which they use to spit out debug information.

Enjoy!

Wednesday, July 23, 2008

webdev.webserver.exe has stopped working

Yesterday I had opened up my Visual Studio 2008 solution which contains a couple of web sites, a WCF project, and some other project types. I am currently using the Cassini web server, since we have a couple of developers who do some work for us off an on and they share a single server using terminal services to do their work.

When I tried to browse a page in my site, I was prompted with a wonderful crash dialog indicating: webdev.webserver.exe has stopped working. This continued no matter how often I tried or rebooted.

I am not sure why the failure occured, but I noticed a coupled things:

  • A new web site in a new solution worked fine

  • My existing web sites in a new solution did not work

  • The event log had the following message: Fault bucket 158894065, type 5
    Event Name: CLR20r3
    Response: None
    Cab Id: 0

    Problem signature:
    P1: webdev.webserver.exe
    P2: 9.0.0.0
    P3: 4731664b
    P4: System
    P5: 2.0.0.0
    P6: 47577deb
    P7: 2c04
    P8: 40
    P9: System.Net.Sockets.Socket
    P10:



I am not sure of the relevance of P9 but I thought hmm could the port it was using be blocked. Running netstat -a did not show the ports in use but I decided to try and change the ports anyways.

Visual Studio stores all the project settings for a web site in the solution file. To change the default port for a web site you need to find the following line and edit it:

Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "Project Name", "Project Name", "{3BD859EC-9AF2-4866-B43C-EE8AEFF0DF49}"
ProjectSection(WebsiteProperties) = preProject
...Addition project properties....
VWDPort = "58332"
EndProjectSection


After modifying it to use a different port Cassini had no issue launching. Hope someone else finds this helpful. And if you have any idea of additional things I should have looked at please leave a comment!


Edit
Editting a solution file is very easy. Find the solution file, and open it up in your favorite text editor. Then find the port setting setting, and edit it.

Monday, July 21, 2008

Fixing users in SQL2005 after restoring a DB

After you restore a database in SQL Server 2005 to a different server, you will need to fix the login associated with the users in the database this can be done by using the following stored procedure:

exec sp_change_users_login 'AUTO_FIX','UserName'


If you don't do this you will get an error while trying to login as the user. This needs to be done for each user in the database.

Friday, June 27, 2008

Wednesday, June 11, 2008

WSDL For WCF ASP.Net service uses local machine name Part II

Something I discovered while doing this is that a WCF service can only be hosted in a site which has a single binding. Based on some forum posts it sounded like this was by design. What this means is that if you are using for example multiple host headers to get to your site, you will not be able to host your WCF service in the web.

There was a blog posting which I have since lost which showed one potential solution which was to use filtering; however in my case I opted to split the service out from the rest of my web which was my original intent anyways.

- Josh

Monday, June 9, 2008

WSDL For WCF ASP.Net service uses local machine name

I've finally found myself with an opportunity to develop and deploy my first WCF service. I know I am several years behind the game but that's what happens when you work for a company which becomes stagnant in their adoption of technology (It is so nice to once again be back with a small and nimble startup).

There are some good articles on deploying a WCF service to IIS on MSDN. Which I recommend reading. I ran into an issue in the the wsdl for my service was using the localmachine name for all the bindings. The autogenerated page you get when you navigate to the .svc page said use: svcutil.exe http://[machinename]/MyService.svc to generate a proxy.

I discovered that in order to get the real URL in here (And within the WSDL for the imports), I needed to set a host header with my domain name. See KB 324287 for more information on how to do this. Once I had configured the host header I was all set.

If you need to do this for a service which is hosted on SSL, you can try the directions from the following blog which gave me the idea to try this for non-ssl ports.

Friday, May 23, 2008

TypelibBuilder.exe Crashes & Javascript Intellisense

Edited: Read an update on getting a resolution to this issue at: http://jberke.blogspot.com/2008/10/typelibbuilderexe-crashes.html.

Edited: Read the final update on this issue:
http://jberke.blogspot.com/2008/10/typelibbuilderexe-crashes_21.html



I've been fairly happy with VS 2008; however, one feature which has never worked right for me is javascript intellisense. It seemed that no matter what I did, as soon as I dropped a ScriptManager on a page, or added an external reference, I'd get a windows error dialog popup telling me TypelibBuilder has crashed.

After searching around and trying some of the suggested solutions which were all from the beta version of VS. I still had the error. I filled an issue on Microsoft Connect, and after some time, was contact by a Microsoft Developer. By the way this developer gave me some of the best support I've ever had from a third party so hats of to you :-).

The underlying issue appears to be a conflict between the biometric software called DigitalPersona and TypeLibBuilder. Nothing has been confirmed but if your having the same issue, and you have a process called DPAgent.exe. Kill the process and your javascript intellisense will probally start working again.

There is no patch available yet; however, I will update this post once one is available. Hopefuly this post will help save you the months of annoyance and frustration. If it did leave a comment, I'm interested to know how many people might be impacted by this.

Enjoy
-Josh

Friday, May 2, 2008

Microsoft Expression Professional Subscription

Microsoft recently announced the RTM of Expression Studio 2, and a new way to buy Expression via a Professional Subscription which appears simillar to MSDN. What I find interesting is what they include with this license:

  • Expression® Studio
  • Visual Studio® Standard
  • Office Standard
  • Office Visio® Professional
  • Windows® XP
  • Windows Vista® Business Edition
  • Virtual PC
  • Parallels Desktop for Mac
  • Pre-configured virtualized server environments

I think it is good that they are embracing the Macintosh platform by including Parallels, at the very least this is a good business decision on their part. The thing I find the most interesting is that they are including a license for Windows XP.