Category Archives: Code

Software Development

Use SqlExpress or Sql Server for Asp.Net Session

Problems using Sql Server or Sql Express for Asp.Net Session State

So you’ve run aspnet_regsql.exe -S .\SqlExpress -E -ssadd -sstype p or something like that, after following instructions about Asp.Net Session State Modes (in particular noting the instructions about the Agent XP setting for SqlExpress if you’re using SqlExpress) and you’ve set your web.config sessionState section; and you hoped that aspnet_regsql might do something useful like give permissions to your machine’s AspNet account to use the session state and it would all Just Work. Aaah. You can hope.

Error messages when setting up Asp.Net to use SqlServer Session State

Cannot open database requested in login ‘ASPState’. Login failed for user {MachineName}\ASPNET

Unable to use SQL Server because ASP.NET version 2.0 Session State is not installed on the SQL server. Please install ASP.NET Session State SQL Server version 2.0 or above

Failed to login to session state SQL server for user ‘AspNetSqlLogin’

Example Web.Config section

<sessionState
    cookieless="false"
    regenerateExpiredSessionId="true"
    mode="SQLServer"
    timeout="30"
    sqlConnectionString="Data Source=.\SqlExpress;Integrated Security=SSPI;"
    stateNetworkTimeout="30">

Solution: Give permissions on Sql Server to your AspNet account

Note the username from your error page telling you what account Asp.Net is using to login to your server. Then, in Sql Management Studio or somesuch:

  1. Create a login for that Windows user
  2. Add the login as a user to your AspState database
  3. Give permissions to that user in that database by making it a member of the owner role

I first tried making the AspNet account a member of the db_reader & db_writer roles, but that didn’t work; making it a database owner did work.

But I put SessionState on a Sql Server instance on a different machine

Then you’re hopefully running your servers within a domain and you can set Asp.Net to run under a domain account, and you can give permissions on Sql server to that domain account.
Or, you create a new Sql Server login. Similar to the above process, but instead of finding an existing Windows login in Sql Management Studio, you create a new Sql Server login). The you specify a connection string with a Sql Security instead of Integrated Security: sqlConnectionString="Data Source=.\SqlExpress;User Id=SqlLoginForAspNet;Password=XXXXXX;

But I get a

Failed to login to session state SQL server for user

and

Login failed for user ‘AspNetSqlLogin’. The user is not associated with a trusted SQL Server connection

That’s because your Sql Server has been configured for Windows Authentication Mode only. Configure it for both Windows and Sql Server Authentication Mode via the Database Properties – Security tab.
When the Gui tells you to restart Sql Server you can do so like this:
[dos]net stop “Sql Server (SQLExpress)”
net start “Sql Server (SQLExpress)”[/dos]
Or do it from Control Panel — Services.

Visual Studio creates unwanted directories for a new solution

So, all you want is to create a new visual studio project called MyProject in a SINGLE directory called MyProject. But behold, Visual Studio has created a million levels of directories called \MyProject\MyProject\MyProject for your project. And put it all all in source control to boot.
Simples:

  1. Specify your project name
  2. Specify the parent directory for MyProject
  3. Untick ‘Create Solution Directory

Visual Studio Create Project dialog highlighting the input fields for project name, existing parent directory and the unticked Create Solution Directory option

Visual Studio Create Project dialog


Voila.

TFS Merge goes funny unless you get latest version

Users of some other source control software are used to the fact that, any merge operation requires a workspace and if that workspace is on your local machine then you need to make sure it’s up-to-date with the branch it is a workspace for before merging into that branch.

TFS is less up front about this, but it does still use your local workspace as a workspace for merge. Therefore:

Before doing a merge with TFS, get latest of the target branch. Then start your merge.

For the paranoid: get specific version — Latest Version; and tick both ‘overwrite’ options.

How to Log WCF Message Bodies to Enterprise Library

Boy, was this painful. But there’s not much too it when it works. There are several bits of config, 3 classes and some gotchas involved, as follows.

Config Sections

<system.serviceModel>
    <extensions>
      <behaviorExtensions>
        <!-- Gotcha: this element looks so easy but is a pain in the backside. 
             The type element has to *exactly* match the undocumented-and-fussier-than-anywhere-else-in-config required format
             If it has to change, the best way to do it is to delete the line and then use MS Service Configuration Tool to lookup the assembly and classname
             See e.g. http://stackoverflow.com/questions/1163996/adding-a-custom-wcf-behavior-extension-causes-a-configurationerrorsexception
             -->
        <add name="EnterpriseLibraryClientMessageBodyLogging"
type="MyNamespace.MyAppName.Implementation.LoggingServiceClientDecorators.EnterpriseLibraryMessageBodyLoggingClientBehaviorExtension, MyNamespace.MyAppName.Implementation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      </behaviorExtensions>
    </extensions>

    <behaviors>
      <endpointBehaviors>
        <behavior name="LogAllMessageBodies">
          <EnterpriseLibraryClientMessageBodyLogging />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <client>
      <!-- Add atrribute 
          behaviorConfiguration="LogAllMessageBodies"
          to the endpoint element to enable WCF message in-and-out logging
          e.g.:
      -->
      <endpoint address="http://10.1.2.3/CalledServiceName/CalledServiceMethod.asmx"
          binding="basicHttpBinding" bindingConfiguration="UnsecuredBindingConfiguration"
          contract="CalledServiceMethod.CalledServiceMethodSoap"

          behaviorConfiguration="LogAllMessageBodies"

          name="CalledServiceMethodSoap"/>

      ... rest of your client section .....
    </client
... rest of your system.serviceModel section ...
</system.serviceModel>
  <loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">
    <listeners>
      <add name="FullFlatFileTraceListener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.RollingFlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging"
        rollSizeKB="5000" rollFileExistsBehavior="Overwrite" timeStampPattern="yyyy-MM-dd" 
listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.RollingFlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging"
        fileName="FullLog.log" formatter="FullTextFormatter" />
    </listeners>
    <formatters>
      <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging"
        template="---------------------------------{newline}Timestamp: {timestamp}{newline}Message: {message}{newline}{newline}Extended Properties: {newline}{dictionary(  {key}: {value}{newline})}"
        name="FullTextFormatter" />
    </formatters>
    <categorySources/>
    <specialSources>
      <allEvents switchValue="All" name="All Events">
        <listeners>
          <add name="FullFlatFileTraceListener"/>
        </listeners>
      </allEvents>
      <notProcessed switchValue="Off" name="Unprocessed Category" />
      <errors switchValue="Off" name="Logging Errors &amp; Warnings" />
    </specialSources>
  </loggingConfiguration>

Code

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using Logger=namespaceWhichDefinesYourLoggerInterfaceIfAny;

namespace blah.LoggingServiceClientDecorators
{
    public class EnterpriseLibraryMessageBodyLoggingClientBehaviorExtension : BehaviorExtensionElement
    {
        protected override object CreateBehavior()
        {
            return new EnterpriseLibraryMessageBodyLoggingClientBehavior();
        }

        public override Type BehaviorType
        {
            get { return typeof (EnterpriseLibraryMessageBodyLoggingClientBehavior); }
        }
    }

    public class EnterpriseLibraryMessageBodyLoggingClientBehavior : IEndpointBehavior
    {
        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(
                new MessageBodyLoggingClientMessageInspector(new EnterpriseLibraryExceptionHandlingLogger())
                );
        }

        #region Irrelevant IEndpointBehavior Members
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { }
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint,EndpointDispatcher endpointDispatcher){}
        public void Validate(ServiceEndpoint endpoint){}
        #endregion
    }

    public class MessageBodyLoggingClientMessageInspector : IClientMessageInspector
    {
        private readonly ILogger logger;

        public MessageBodyLoggingClientMessageInspector(ILogger logger)
        {
            this.logger = logger;
        }

        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
            logger.Info("<MessageRecord Direction=\"In\">{0}</MessageRecord>", reply.ToString());
        }

        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            logger.Info("<MessageRecord Direction=\"Out\" Endpoint=\"{1}\">{0}</MessageRecord>", request.ToString(), channel.RemoteAddress.Uri);
            return null;
        }
    }
}

The Gotchas

  1. Note this is a completely different route to what you’ll find if you search for ‘WCF message logging’ What you’ll find there is how to switch on WCF logging. Which logs everything – and I mean everything – except the message bodies.
  2. The typename in the behaviorExtensions section above is hard to type exactly as required
  3. The typename in the behaviorExtensions must specify an exact version number which is a pain when it changes
  4. Note that you can’t do anything more sophisticated with the messages in the IClientMessageInspector because by design Messages are Read Once. If you want to extract the innards of the message, you have to copy it to a buffer, then and set the ref parameter to a new copy of the message.