New Blog Location

I’ve moved this blog to GitHub Pages located here:

http://patrickhuber.github.io/

Advertisements

Web Api 2, Oracle and Entity Framework

I spent about two days trying to figure out how to expose the Oracle.ManagedDataAccess 4.121.1.0 library over a Web Api 2.2 OData v4 Endpoint. Looking through the Oracle documentation, Oracle Managed Data Access doesn’t currently support Entity Framework v6, so you have to use Entity Framework v5. DevArt supplies a Entity Framework 6 compatible product, unfortunately I didn’t have the time to get budget for this simple proof of concept and I haven’t had much luck with trial periods as they never seem to be active when I need them. When Oracle releases the ODP.NET 12c r3 libraries later summer 2014, this post will be deprecated as it comes with EF 6 support.

First thing is to install Entity Framework via NuGet Package Manager

Install-Package EntityFramework -Version 5.0.0

Next you need to install WebApi v2.2 with OData support.

Install-Package Microsoft.AspNet.OData

Finally you need to install the Oracle.ManagedDataAccess library, which is called ODP.NET.

Install-Package odp.net.managed

Now that all of the packages are installed, the oracle connection strings need to be setup. I had issues connecting to oracle 11g with the default “Data Source = xyz; user id= myuser; password = abcd123” connection string. I received an error:

ORA-12154: TNS:could not resolve the connect identifier specified

Doing some research, you get this error when Oracle can not find the list of registered oracle servers on your network. I remember Sql Server having a discovery protocol similar to this, but I guess that the port numbers are not consistent the way they are in the Microsoft world so you have to go and specify the direct network location in the connection string.

Documentation stated that you should be able to install ODP.NET and point to the TnsNames.ora file to get the connection information. The TnsNames.ora file looks to be configured after the install, so I guess I got lucky there. Consulting with your Oracle DBA may help you locate the information for your server. This stackoverflow post gave me the connection string structure based on the ora file. You can’t just copy the values directly in there, you have to remove the Alias.

I wanted to configure the connection string in my web.config file instead of specifying it directly. To do that, you need the Oracle.ManagedDataAccess.Client.OracleClientFactory provider to be specified in the providerName field of the configuration file.


<connectionStrings>
<add name="myConnectionString" connectionString="from stackoverflow article" providerName = "Oracle.ManagedDataAccess.Client"/>

Adding this I received an error “Failed to find or load the registered .Net Framework Data Provider.”. This error occurs when the Oracle.ManagedDataAccess.Client.OracleClientFactory class isn’t registered in the web.config or machine.config. I don’t like putting assemblies in the GAC on production servers, so I’m glad this showed up on my workstation and not later in the release cycle. Adding the following to the configuration file resolved the error:


<system.data>
<DbProviderFactories>
<add name="Oracle ManagedDataAccess Provider"
invariant="Oracle.ManagedDataAccess.Client"
description=".Net Framework Data Provider for Oracle"
type="Oracle.ManagedDataAccess.Client.OracleClientFactory, Oracle.ManagedDataAccess" />
</DbProviderFactories>
</system.data>

With Entity Framework working, its time to focus on WebApi. Following any number of tutorials on the subject can get you stated, I used this one.

I made a few tweaks adding ODataRoutePrefixAttribute to my controller and ODataRoute to my action, but otherwise it is the same.

Visualize the TPL Dataflow Predefined Blocks as Pixel Art

I’ve been messing around with the TPL Dataflow and found I was visualizing the block types when reading the descriptions here http://msdn.microsoft.com/en-us/library/hh228603(v=vs.110).aspx

I did a quick sketch up using simple pixel art. 

 Image 

In order we have 

Buffer Blocks

  • BufferBlock
  • BroadcastBlock
  • WriteOnceBlock

Execution Blocks

  • ActionBlock
  • TransformBlock
  • TransformManyBlock

Grouping Blocks

  • BatchBlock
  • JoinBlock
  • BatchedJoinBlock

Visualization helps me when learning new concepts, so hopefully this helps others who are having trouble picking a block for a dataflow.

 

ASP.NET User Principal assignment to thread.

I’ve been digging into our legacy codebase that does custom identity management and ran into a question I had trouble answering.

Q: Does ASP.NET assign a user to the thread on every request?
A: Yes.

I did a simple demo using the MVC3 template with a fake membership provider.

In Global.asax.cs

private void LogUserState(string method, object sender, EventArgs e)
{
	var application = sender as HttpApplication;
	if (application == null)
		return;

	if (application.User == null || application.User.Identity == null)
		Trace.WriteLine(string.Format("{0}: Current User is Missing. Thread ID {1}", method, Thread.CurrentThread.ManagedThreadId));
	else
		Trace.WriteLine(string.Format("{0}: Current User is {1}. Thread ID {2}", method, application.User.Identity.Name, Thread.CurrentThread.ManagedThreadId));
}

protected void Application_BeginRequest(object sender, EventArgs e)
{
	LogUserState(MethodInfo.GetCurrentMethod().Name, sender, e);
}

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
	LogUserState(MethodInfo.GetCurrentMethod().Name, sender, e);
}

protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
	LogUserState(MethodInfo.GetCurrentMethod().Name, sender, e);
}

Output is as follows

Application_BeginRequest: Current User is Missing. Thread ID 38
Application_AuthenticateRequest: Current User is abc123. Thread ID 38
Application_PostAuthenticateRequest: Current User is abc123. Thread ID 38

Razor View Error Sitecore.Mvc.AssemblyInitializer in Area project Sitecore 6.6 Technical Preview

Using Sitecore 6.6 technical preview I get the following error in the Razor view engine and its breaking my intellisense.

ASP.NET runtime error: The pre-application start initialization method InitializeAssembly on type Sitecore.Mvc.AssemblyInitializer threw an exception with the following error message: Could not read Sitecore configuration..

Our project uses heavy customization and MVC Areas to allow for a plugin type architecture. We have area projects that contain the MVC assets and views for the plugin and the intellisense was broken in one of those projects. It appears that the Sitecore.Mvc.AssemblyInitializer method is a bootstrapped method that runs during the Razor parsing of the view file in order to build the references necessary to show the intellisense.

A simplified example, where intellisense is broken in the PluginProject:

  • Solution
    • PluginProject
      • Web.config
    • SiteProject
      • App_Config
        • Include
          • Event.config
        • ConnectionStrings.config
      • Web.config

I originally thought the issue was due to an MVC 4 installation, but removing the install did nothing to fix the issue. Turns out the error message (as usual) is the key. The Sitecore.Mvc.AssemblyInitializer method is looking for the sitecore configuration in the area project web.config, which it can’t find in the portable area project because the configuration is in the main web.config of the site project.

Since we only require a reference to the Sitecore.Mvc.dll and not for that dll to be in the area project bin directory, I deleted the file and set the reference to “copy local = false”. The bootstrapper for Razor now doesn’t see the Sitecore.Mvc.dll in the bin directory and the error goes away.

Running Sitecore Agents with Sitecore Powershell Console

We recently needed to execute the Sitecore agent for cleaning the event queue because it wasn’t running on its own.

We are using Sitecore 6.6

First of all, install Powershell for Sitecore. http://marketplace.sitecore.net/en/Modules/Sitecore_PowerShell_console.aspx

Once that is installed, go into sitecore and start the PowerShell console.

In the powershell console, type:

PS master:\> $cleanupEventQueue = new-object Sitecore.Tasks.CleanupEventQueuentQueue
PS master:\> $cleanupEventQueue.DaysToKeep = 1
PS master:\> $cleanupEventQueue.Run()

This will run the code for the task to cleanup the queue. There are other tasks defined in the agent section of the configuration that can be run the same way. For example, we also run the CleanPublishQueue keeping 30 days.

PS master:\> $cleanupPublishQueue = new-object Sitecore.Tasks.CleanupPublishQueue
PS master:\> $cleanupPublishQueue.DaysToKeep=30
PS master:\> $cleanupPublishQueue.Run()

Unit Testing Sitecore MVC with Glass Mapper

I work on a large Sitecore 6.6 MVC project and we have been spending a lot of time thinking about Unit Testing with Sitecore.

The big issue, for anyone familiar with Unit Testing MVC, is that static contexts make unit testing difficult. Traditional Sitecore development involves heavy use of the static ‘Sitecore.Context’ to perform almost every operation. Static Context doesn’t change much in Sitecore’s MVC extension, with the use of PageContext and Rendering Context to fetch where you are in the site, and Sitecore.Context to perform queries.

Some have tried to solve this problem by creating a Sitecore Service concept and mocking out the Item and Field classes with an adapter pattern. The one issue we faced was that we still had lots of mapping between these interfaces and our POCO objects that represented the models.

We looked around at various blog posts and even had a conversation with Sitecore about the topic. The general consensus was that Glass Sitecore Mapper makes Unit Testing easier, but we noticed a recurring pattern in our development.

public class PromotionsController : Controller
{
   public ActionResult Index()
   {
       // resolve the Glass Sitecore Service
       // this could also be done by resolving as a controller dependency
       ISitecoreService sitecoreService = DependencyResolver.Current.GetService<ISitecoreService>();

       // this is the failover id which is the default
       Guid dataSource = Constants.SitecoreTree.Content.Sites.Global.Data.Demos.DataSource;

       // rendering context shouldn't be null if we are using a rendering
       if(RenderingContext.CurrentOrNull != null
          && RenderingContext.Current.Rendering != null
          && RenderingContext.Current.Rendering.Item != null)
       {
           dataSource = RenderingContext.Current.Rendering.Item.ID.Guid;
       }

       // fetch the demo model from the Sitecore service
       Promotion promotionModel = sitecoreService.GetItem<Promotion>(dataSource);
       return View(promotionModel);
   }
}

Our model would look something like this


[SitecoreClass]
public class Promotion
{
    [SitecoreId]
    public virtual Guid Id { get; set; }

    [SitecoreField("Promotions")]
    public virtual IEnumerable<PromotionItem> Items { get; set; }
}

[SitecoreClass]
public class PromotionItem
{
    [SitecoreId]
    public virtual Guid Id { get; set; }

    [SitecoreField]
    public virtual string Title { get; set; }

    [SitecoreField]
    public virtual string Description { get; set; }

    [SitecoreField]
    public virtual Glass.Sitecore.Mapper.FieldTypes.Image Image { get; set; }

    [SitecoreField]
    public virtual Glass.Sitecore.Mapper.FieldTypes.Link Action { get; set; }
}

Looking at the above code, we see that we are doing the same operations over and over

  1. Resolve ISitecoreService
  2. Set Default Item ID
  3. If RenderingContext is Present, override Default Item ID
  4. Use datasource to fetch item using ISitecoreService
  5. Return to View

MVC provides many extension points to plug-in common code. For this particular set of logic, we decided to use a Model Binder. The Model Binder syntax can be a bit verbose using the default values, we wanted something that was concise and described what we were using to accomplish model binding. This resulted in the ‘GlassAttribute’.

public class GlassAttribute
    : CustomModelBinderAttribute, IModelBinder
{
    public string DataSource { get; set; }

    public GlassDataSourceBehavior Behavior { get; set; }

    public override IModelBinder GetBinder()
    {
        return this;
    }

    public virtual object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        // get the model type
        var modelType = bindingContext.ModelType;

        // get the sitecore service
        ISitecoreService sitecoreService = DependencyResolver.Current.GetService();
        if (sitecoreService == null)
                throw new Exception("Unable to resolve dependency for Glass.Sitecore.Mapper.ISitecoreService. Register the interface once in the global application, or in the AreaRegistration.");

        Guid dataSourceId = Guid.Empty;
        string dataSourcePath = string.Empty;

        // check if its an ID or path
        if (!Guid.TryParse(DataSource, out dataSourceId))
            dataSourcePath = DataSource;

        // do some workflow
        if (Behavior == GlassDataSourceBehavior.Failover)
        {
            // get the current rendering context id
            // uses monads http://nuget.org/packages/Monads
            var currentId = RenderingContext.CurrentOrNull
                .With(x => x.Rendering)
                .With(x => x.Item)
                .With(x => x.ID)
                .Return(x => x.Guid, Guid.Empty);

            // if the current id is not null, use it for the datasource
            if (currentId != Guid.Empty)
                dataSourceId = currentId;
        }

        // do we have an id?
        if (dataSourceId != Guid.Empty)
            return sitecoreService.GetItem(modelType, dataSourceId);

        // do we have a path?
        if (!string.IsNullOrWhiteSpace(dataSourcePath))
            return sitecoreService.GetItem(modelType, dataSourcePath);

        // no item found to bind
        return null;
    }
}

And the data source behavior

public enum GlassDataSourceBehavior
{
    Failover,
    Override
}

We also need to extend the ISitecoreService to use System.Type instead of generics.


public static class ISitecoreServiceExtensions
{
    public static object GetItem(this ISitecoreService service, Type type, string path)
    {
        MethodInfo getItemMethod = typeof(ISitecoreService).GetMethod("GetItem", new Type[] { typeof(string) }, null);
        MethodInfo genericGetItemMethod = getItemMethod.MakeGenericMethod(type);

        return genericGetItemMethod.Invoke(service, new object[] { path });
    }

    public static object GetItem(this ISitecoreService service, Type type, Guid id)
    {
        MethodInfo getItemMethod = typeof(ISitecoreService).GetMethod("GetItem", new Type[] { typeof(Guid) }, null);
        MethodInfo genericGetItemMethod = getItemMethod.MakeGenericMethod(type);

        return genericGetItemMethod.Invoke(service, new object[] { id });
    }
}

Here is a example of use.

public ActionResult Index([Glass]Promotion promotionModel)
{
    return View(promotionModel);
}

Most use cases will just contain the [Glass] attribute, but we added a failover for cases when the rendering datasource isn’t set in Sitecore. The logic in the glass attribute may need some tweaking in the Failover scenario. The RenderingContext.CurrentOrNull.Rendering.Item automatically fails over to the PageContext so we have had a discussion about adding a Behavior for using the user specified datasource when the Rendering is missing a datasource in case the user wants to catch binding before the PageContext is used.

A failover scenario would look like the following


// DataSource constant should now be a string
public ActionResult Index([Glass(
   DataSource=Constants.SitecoreTree.Content.Sites.Global.Data.Demos.DataSource)]Promotion promotionModel)
{
    return View(promotionModel);
}

An override scenario would look like the following

// DataSource constant should now be a string
public ActionResult Index([Glass(
DataSource=Constants.SitecoreTree.Content.Sites.Global.Data.Demos.DataSource,
Behavior=GlassDataSourceBehavior.Override]Promotion promotionModel)
{
    return View(promotionModel);
}

We now have a controller action that is capable of being unit tested. Depending on how deep you go with unit tests, you could write a unit test for the GlassAttribute as well.