Skip to content
Archive of posts filed under the Entity Framework category.

Creating WCF Service with SOAP/REST Endpoints

In this post I am going to describe a solution to the following problem.  I would like to create a single WCF Service and expose it via a standard SOAP endpoint and REST endpoint using Entity Framework, WCF and WCF REST.  Then I would like to consume it from WinRT from two different view models working against the same view.  This is an exercise of research into data options in WinRT.

First of, let’s create a service.  I am going to use the following data class:

    public class Session
    {
        public int SessionID { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public string Speaker { get; set; }
        public DateTime When { get; set; }
    }

My data context for EF Code First is just as simple:

    public class Context : DbContext
    {
        public Context() :
            base("Name=VSLive")
        {
        }
        public DbSet<Session> Sessions { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<Session>().Property(p => p.Title).HasMaxLength(100).IsRequired();
            modelBuilder.Entity<Session>().Property(p => p.Speaker).HasMaxLength(50).IsRequired();
            modelBuilder.Entity<Session>().Property(p => p.Description).IsRequired();
            modelBuilder.Entity<Session>().Property(p => p.When).IsRequired();
        }
    }

Now, the service.  I am just going to perform basis CRUD opertions.  The key to the service is my interface that I am going to decorate with both SOAP(OperationContract) and REST(WebGet or WebInvoke) attributes.

    [ServiceContract]

    public interface IVSLiveService
    {
        [OperationContract]
        [WebGet(UriTemplate = "/GetList", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        Session[] GetList();

        [OperationContract]
        [WebInvoke(UriTemplate = "/Create", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        Session Create(Session session);

        [OperationContract]
        [WebInvoke(UriTemplate = "/Update", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        Session Update(Session session);

        [OperationContract]
        [WebInvoke(UriTemplate = "/Delete?sessionId={sessionId}", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        void Delete(int sessionId);

    }

The implementation is not quite as interesting, but for the same of completeness of this post, here it goes:

using System.Data.Entity;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;
using WinRT.Data;
using WinRT.DataAccess;

namespace WcfService
{
    [AspNetCompatibilityRequirements(
      RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class VSLiveService : IVSLiveService
    {
        public VSLiveService()
        {
            Database.SetInitializer(new Initializer());
        }

        public Session[] GetList()
        {
            using (var context = new Context())
            {
                context.Configuration.LazyLoadingEnabled = false;
                context.Configuration.ProxyCreationEnabled = false;
                return context.Sessions.ToArray();
            }
        }

        public Session Create(Session session)
        {
            using (var context = new Context())
            {
                context.Sessions.Add(session);
                context.SaveChanges();
            }
            return session;
        }

        public Session Update(Session session)
        {
            using (var context = new Context())
            {
                context.Entry(session).State = System.Data.EntityState.Modified;
                context.SaveChanges();
            }
            return session;
        }

        public void Delete(int sessionID)
        {
            using (var context = new Context())
            {
                var session = new Session { SessionID = sessionID };
                context.Entry(session).State = System.Data.EntityState.Deleted;
                context.SaveChanges();
            }
        }
    }
}

Now, the part that took me the longest to figure out: web.config.

I have single service node, and I have two endpoints for it, using the same contract, but two different bindings and behaviors.  I am putting entire web.config:

<?xml version="1.0"?>
<configuration>
  <connectionStrings>
    <add
          name="VSLive"
          connectionString="Server=.;Database=VSLive;Trusted_Connection=True;"
          providerName="System.Data.SqlClient"/>
  </connectionStrings>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="jsonBehavior">
          <webHttp/>
        </behavior>
      </endpointBehaviors>

      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!—To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <basicHttpBinding>
        <binding
          name="VSLiveService_BasicHttpBinding"
          maxBufferSize="1000000"
          maxReceivedMessageSize="1000000">
          <readerQuotas
            maxBytesPerRead="1000000"
            maxArrayLength="1000000"
            maxDepth="1024"
            maxStringContentLength="1000000"/>
        </binding>
      </basicHttpBinding>
      <webHttpBinding>
        <binding
           name="VSLiveService_WebHttpBinding"
           maxBufferSize="1000000"
           maxReceivedMessageSize="1000000">
          <readerQuotas
            maxBytesPerRead="1000000"
            maxArrayLength="1000000"
            maxDepth="1024"
            maxStringContentLength="1000000"/>
        </binding>
      </webHttpBinding>

    </bindings>
    <services>
      <service name="WcfService.VSLiveService">
        <endpoint
          address="soap"
          binding="basicHttpBinding"
          bindingConfiguration="VSLiveService_BasicHttpBinding"
          contract="WcfService.IVSLiveService"/>
        <endpoint
            address="rest"
            binding="webHttpBinding"
            behaviorConfiguration="jsonBehavior"
            bindingConfiguration="VSLiveService_WebHttpBinding"
            contract="WcfService.IVSLiveService"/>
      </service>
    </services>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel"
              switchValue="Information, ActivityTracing"
              propagateActivity="true">
        <listeners>
          <add name="traceListener"
              type="System.Diagnostics.XmlWriterTraceListener"
              initializeData= "c:\Traces.svclog" />
        </listeners>
      </source>
    </sources>
  </system.diagnostics>
</configuration>

As you can see above, SOAP endpoint comes first, and it is using basicHttpBinding.  My REST endpoint is second, and it is using webHttpBinding  I am asing a behavior configuration to the latter one, enabling webHttp get/post methods.

This is all nice and simple, and you can now test it in browser.  I an now add service reference to my WinRT project to support WCF.  You can find more details about that in my previous post http://dotnetspeak.com/index.php/2011/12/getting-started-with-wcf-services-in-winrt/

Today, I am documenting REST consumption.

I am using HttpClient class to accomplish this task.  For example, here is how I am going to get the list of sessions.

        public async Task LoadData()
        {
            IsBusy = true;
            _client = new HttpClient();
            _client.MaxResponseContentBufferSize = int.MaxValue;
            var response = await _client.SendAsync(new HttpRequestMessage(HttpMethod.Get, new Uri(_serviceUri + "GetList")));

            var data = response.Content.ReadAsString();

            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<Session>));
            using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(data)))
            {
                var list = serializer.ReadObject(stream) as List<Session>;
                Sessions = new ExtendedObservableCollection<Session>(list);
            }
            IsBusy = false;
        }

A few points about the code above.  I should have wrapped the call inside Try/Catch, I am just skipping it for the sake of a demo and to minimize the code I am showing.  I am using standard serializer to convert my JSON message into an object.  I also have a little progress ring that is playing while server communication is going on, and that is what my IsBusy property above is bound to. 

Now, let’s take a look at Create/Update call.  It is just as simple, but I am using Post method of HttpClient and I am creating a string content to post by converting Session object to JSON, again using the same serializer.

        public async void OnSave(object parameter)
        {
            if (SelectedSession != null)
            {
                IsBusy = true;
                string method = "Update";
                if (selectedSession.SessionID == 0)
                {
                    method = "Create";
                }
                _client = new HttpClient();
                _client.MaxResponseContentBufferSize = int.MaxValue;
                var content = new StringContent(ConvertSessionToJson());
                content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
                var response = await _client.PostAsync(new Uri(_serviceUri + method), content);

                var data = response.Content.ReadAsString();

                var session = ConvertJsonToSession(data);
                Sessions[Sessions.IndexOf(selectedSession)] = session;
                SelectedSession = session;
                IsBusy = false;
            }
        }

For delete method I am also using Post method, just my content is blank and my ID is passed to the server as query string parameter

        public async void OnDelete(Session parameter)
        {
            if (parameter != null)
            {
                if (parameter.SessionID > 0)
                {
                    IsBusy = true;
                    _client = new HttpClient();
                    _client.MaxResponseContentBufferSize = int.MaxValue;
                    var content = new StringContent(string.Empty);
                    content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
                    var response = await _client.PostAsync(new Uri(_serviceUri + "Delete?sessionId=" + parameter.SessionID.ToString()), content);

                    var data = response.Content.ReadAsString();
                    Sessions.Remove(parameter);
                    IsBusy = false;
                }
                else
                {
                    Sessions.Remove(parameter);
                    IsBusy = false;
                }
            }
        }

Please let me know your questions.

Thanks.

Post to Twitter

Implementing Error Handling in ASP.NET MVC

In this post I am going to try to document the solution to the following problem. I would like to implement custom global error handling in my ASP.NET MVC application using entity framework to log errors into the database.  Once the error is logged, I want to redirect the user to the custom page that will contain the newly generated error number so that they can contact support and give them more information about the error.

I am going to start with defining a custom error table in my DbContext.  In my case I am going to keep it simple, but you can add any custom columns you would like as long as you can get to the data from your executing application.

Here is how I am going to define my table and context

 

using System;

using System.ComponentModel.DataAnnotations;

 namespace MvcEFCodeFirst.Data

{

    public class AppError

    {

        public int AppErrorID { get; set; }

        public DateTime ErrorDateTime { get; set; }

        [StringLength(250)]

        public string UserIdentity { get; set; }

        public string ErrorText { get; set; }

    }

}

Of course, you can add any other columns you would like that suits your use case.  Then I add this table to my context via a new property:

public DbSet<AppError> AppErrors { get; set; }

Now, I am going to write the key part of the solution – my global error handler object.  It must do the following tasks:

  • Get the last error information
  • Log it into the table above
  • Redirect to the controller that will show a message to the user along with newly generated error (incident) number

The class is pretty simple, and works mostly on HttpContext.Current class to get the information it needs:

using System;

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

using System.Web.Routing;

using MvcEFCodeFirst.Controllers;

using MvcEFCodeFirst.Data;

using MvcEFCodeFirst.DataAccess;

namespace MvcEFCodeFirst.Helpers

{

    public static class ErrorHandler

    {

        public static void HandleError()

        {

            try

            

                // get the last error

                var exception = HttpContext.Current.Server.GetLastError();

                // clear out error information and any pending responses

                HttpContext.Current.Server.ClearError();

                HttpContext.Current.Response.Clear();

                // create new error to log

                var error = new AppError

                {

                    ErrorDateTime = DateTime.Now

                    ErrorText = exception.ToString(),

                    UserIdentity = HttpContext.Current.User.Identity.Name

                }

                // log error

                using (var context = new CodeStockContext())

                {

                    error = context.AppErrors.Add(error)

                    context.SaveChanges()

                }

                // redirect to error ErrorController.Index method

                // and pass in application error object so that the controller

                // could add error number to the page

                var routeData = new RouteData();

                routeData.Values.Add("controller", "Error");

                routeData.Values.Add("action", "Index");

                routeData.Values.Add("appError", error);

                ((IController)new ErrorController())

                    .Execute(new RequestContext(

                        new HttpContextWrapper(HttpContext.Current), routeData));

            }

            // ReSharper disable EmptyGeneralCatchClause

            catch (Exception)

            // ReSharper restore EmptyGeneralCatchClause

            

                //Ignore errors that occur during loggin

            

        }

    }

}

I added comments to demonstrate what I am doing in this class.

Now. let me show you my error controller, which is very simple and the Index view for it:

using System.Web.Mvc;

using MvcEFCodeFirst.Data;

namespace MvcEFCodeFirst.Controllers

{

    public class ErrorController : Controller

    {

        public ActionResult Index(AppError appError)

        {

            return View(appError);

        }

    }

}

Now, the view

@using MvcEFCodeFirst.Data

@model AppError

<h2>

    Error has occurred</h2>

<h4>

    An error has occurred and has been logged. Error number is @Model.AppErrorID.ToString().

    Please contact technical support.

</h4>

<br /

@Html.ActionLink("Main Menu", "", "")


And a few last steps.  I turn off custom errors in web config since I an implementing them differently now:

<system.web>

    <customErrors mode="Off"/>

</system.web>

And the last step is to call my error handler from Global.asax error handling routine:

using System;

using System.Web.Mvc;

using System.Web.Routing;

using System.Data.Entity;

using MvcEFCodeFirst.DataAccess;

using MvcEFCodeFirst.Helpers;

 
namespace MvcEFCodeFirst

{

    public class MvcApplication : System.Web.HttpApplication

    {

        public static void RegisterGlobalFilters(GlobalFilterCollection filters)

        {

            filters.Add(new HandleErrorAttribute());

        }

 
        public static void RegisterRoutes(RouteCollection routes)

        {

            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

 
            routes.MapRoute(

                "Default",

                "{controller}/{action}/{id}",

                new { controller = "Home", action = "Index", id = UrlParameter.Optional }

            );

 
        }

 
        protected void Application_Start()

        {

            AreaRegistration.RegisterAllAreas();

 
            RegisterGlobalFilters(GlobalFilters.Filters);

            RegisterRoutes(RouteTable.Routes);

 
            Database.SetInitializer(new DbInitializer());

        }

 
 

        protected void Application_Error(object sender, EventArgs e)

        {

            ErrorHandler.HandleError();

        }


    }

}

And that is all there is to it.  I know there is a bunch of other solutions, such as ELMAH, I saw while investigating my possible answers to the problem, but I think this one suits my goals the best.  Of course, you can also retrieve the error code from the exception by casting it to HttpException, but in my case I did not need to do that.  Another option is to use Response.Redirect instead of Controller.Execute, but this is a small variation of the same solution.

Thanks.

Post to Twitter

Entity Framework 4.3 Beta 1 Released

Entity framework team at Microsoft announced the beta release of the next version of Entity Framework Code First package, which now ships with migrations feature.

Read more about this release here
http://blogs.msdn.com/b/adonet/archive/2012/01/12/ef-4-3-beta-1-released.aspx

Thanks.

Post to Twitter

Oracle ODP and Entity Framework Code First (4.2)

Oracle just released its newest version of Oracle Data Access Components (ODAC) that incudes support for Entity Framework 4.0.  You can read more about this release here http://www.oracle.com/technetwork/topics/dotnet/whatsnew/index.html.  You can also read this article about usage of ODP (Oracle Data Provider) with Entity Framework models http://www.oracle.com/technetwork/issue-archive/2011/11-sep/o51odt-453447.html

One important note is that Code First is not officially supported in this release, and will be supported in a future release.  Having said that, I wanted to see if I can use it, since Code First builds on top of EF 4, which is supported by this release.  I was able to confirm that I can indeed access Oracle data and update it. 

Here are step-by-step instructions.

You will need one prerequisite – Oracle engine itself.  I used 11g Express edition, which is free for developer.  You can download it from this page
http://www.oracle.com/technetwork/database/express-edition/downloads/index.html

Event those it is not required, I also installed Sql Developer, which is akin to SQL Server Management Studio, well mostly anyway.  You can download it from this page
http://www.oracle.com/technetwork/developer-tools/sql-developer/downloads/index.html

Once that is done, download and install ODAC from here
http://www.oracle.com/technetwork/topics/dotnet/whatsnew/index.html

At this point, I ran SQL Developer, connected to my instance and looked at the existing database.  You have to create a new connection for that, using File – New..->Database Connection menu. Under Other Users node I found HR, which contains a sample HR database.

image

Personally, I reset password for HR user to something that I know.  This way I do not have to use SYS login.

Now that those tasks are out of the way, you are ready to get started.  I assume you already have VS 2010 installed.

Now, start new project (I used Console application) and install Entity Framework Code First package reference into this project.  You can use NuGet for that, which is what I did.  Also add a reference to Oracle ODP assembly – Oracle.DataAccess.  Then, I create a POCO class to match Countries table and setup DbContext.  I use fluent API to configure that table.  I just do it in the context class instead of creating a separate configuring class.  Here is my country class.


   
public class Country
    {
       
public string CountryID { get; set; }
       
public string CountryName { get; set
; }
       
public decimal RegionID { get; set
; }
    }

 

And here is DbContext class:


   
public class Context : DbContext
    {
       
public Context()
            :
base(new OracleConnection(ConfigurationManager.ConnectionStrings["OracleHR"].ConnectionString), true
)
        {
 
        }
       
public DbSet<Country> Countries { get; set
; }
 
       
protected override void OnModelCreating(DbModelBuilder
modelBuilder)
        {
           
base
.OnModelCreating(modelBuilder);
            modelBuilder.Conventions.Remove<
IncludeMetadataConvention
>();
            modelBuilder.Entity<
Country>().Property(p => p.CountryID).HasColumnName("COUNTRY_ID"
);
            modelBuilder.Entity<
Country
>().HasKey(p => p.CountryID);
            modelBuilder.Entity<
Country>().Property(p => p.CountryName).HasColumnName("COUNTRY_NAME"
);
            modelBuilder.Entity<
Country>().Property(p => p.RegionID).HasColumnName("REGION_ID"
);
            modelBuilder.Entity<
Country>().ToTable("COUNTRIES", "HR"
);
        }
    }
 

 

Now, you have to setup connection string in app.config:

<?xml version="1.0"?>
<configuration>
               <connectionStrings>
                               <add name="OracleHR"
                                               connectionString="DATA SOURCE=localhost:1521/XE;PASSWORD=****;PERSIST SECURITY INFO=True;USER ID=HR;
"
                                               providerName="Oracle.DataAccess.Client" />

               </connectionStrings>
               <startup>
                               <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
               </startup>
</configuration>

 

Here is the code that gets data from the table and inserts a new row.

            using (var ctx = new Context())
            {
               
var
data = ctx.Countries.ToList();
                ctx.Countries.Add(
new Country() { CountryID = "CL", CountryName = "Chile"
, RegionID = 2 });
                ctx.SaveChanges();
            }

 

Here are a few important points.

  • Make sure to put correct password into connection string.
  • I configure column names explicitly to match the database table. 
  • I had to use correct .NET types to match the Oracle data types.  Here is MSDN article that describes this mapping http://msdn.microsoft.com/en-us/library/yk72thhd.aspx
  • I am manually creating Oracle Connection and passing it into constructor of my context class.  I tried to avoid that, but I kept getting exceptions.  This approach worked perfectly.

In summary, one apparently can use newest Oracle provider to use with Code First.  This approach is not officially supported by Oracle, at least not yet.  So, use it at your own risk.  You definitely cannot create new database as you can in SQL Server, so you have to maintain database separately.  From my research, only DevArt provides full Code First support for Oracle with their own provider, at least according to their product page http://www.devart.com/dotconnect/entityframework.html

You can download my sample solution http://DotNetSpeak.com/Downloads/EFOracle.zip

 

Thanks, and feedback is appreciated.

Post to Twitter

VS Live Orlando 2011

As I mentioned before, I presented at VS Live conference in Orlando, FL Thursday, 12/08/2011. I presented the following two talks

Working with Data on Windows Phone 7
I will talk about various approaches to work with data on Windows Phone 7. I will cover all major concepts, such as local storage, OData/WCF Data Services and custom WCF services. I will demonstrate how to retrieve data and save changes locally or to a remove web server. I will build demos for all technologies step-by-step.

You will learn:
• About options to persist the data on Windows Phone 7
• About pros and cons of each technologies
• Knowledge to build a Windows Phone application that publishes and/or consumes data

You can download the materials for this presentation here.

Using Code First (Code Only) Approach with Entity Framework
Session will include high level overview of Entity Framework and how various approaches to use it fit into application development lifecycle. Then I will build POCO classes that entity framework can use to create database as well as perform CRUD operations against the database. Various attributes that are included out of the box will be covered. This will include columns constraints, relationships, etc. I will show you how ASP.ENT MVC 3 can utilize entity framework code first metadata to build automatic validation of user input.
You will learn:
• How to build data access layer with Entity Framework Code First
• About validation approaches using POCO classes
• Fluent API and attribute based configuration option

You can download the materials for this presentation here.  I spent a lot of time answering questions, which I really enjoy, so I ran a bit short on time covering MVC.  On a positive note, you can still see the project in the download zip file.

Feel free to ask any questions related to the presentations in the comments or email me directly.  You can find my email address on Contact Me page on this blog.

Post to Twitter

Update to EF Extras Project

As I blogged about this before, I continue working on my Entity Framework Code First extras project on CodePlex.  Today I added support for indexes to the functionality of the project.  I bumped up the version to 0.9.4.  I wanted an ability to declaratively express indexes on tables via attributes.  So, I added a new attribute to support that:

using System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
 

namespace
EFUtil.Core.Indexes
{
          
/// <summary>

          
/// Used to specify an index for a column
          
/// </summary>
           [
AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
          
public class IndexedAttribute : Attribute

           {
                     
/// <summary>
                     
/// Create new instance of the indexed attribute
                     
/// </summary>
                     
/// <param name="indexName">Name of the index</param>
                     
/// <param name="ordinalPosition">Position of the column in an index</param>
                     
/// <param name="columnName">Column name for the index</param>
                     
/// <param name="direction">Direction of the column sorting in an index</param>
                     
/// <param name="tableName">Table name for the index</param>
                     
public IndexedAttribute(
                                
string
indexName,
                                
int
ordinalPosition = 0,
                                
string columnName = ""
,
                                
IndexDirection direction = IndexDirection
.Ascending,
                                
string tableName = ""
)
                      {
                                 IndexName = indexName;
                                 OrdinalPoistion = ordinalPosition;
                                 TableName = tableName;
                                 ColumnName = columnName;
                                 Direction = direction;
                      }
 
                     
/// <summary>

                     
/// Position of the column in an index
                     
/// </summary>
                     
public int OrdinalPoistion { get; private set; }
 
                     
/// <summary>

                     
/// Direction of the column sorting in an index
                     
/// </summary>
                     
public IndexDirection Direction { get; private set; }
                     
/// <summary>

                     
/// Table name for the index
                     
/// </summary>
                     
public string TableName { get; private set; }
 
                     
/// <summary>

                     
/// Column name for the index
                     
/// </summary>
                     
public string ColumnName { get; private set; }
 
                     
/// <summary>

                     
/// Name of the index
                     
/// </summary>
                     
public string IndexName { get; private set
; }
           }
}

 

This attribute allows you specify all index properties, such as name, direction (ascending or descending) and a column’s ordinal position in the index.  Here is sample usage in a table (class):

using System;
using
EFUtil.Core.Defaults;
using
EFUtil.Core.Indexes;
 

namespace
EFUtil.TestApplication
{
          
public class Product

           {
                     
public int ProductId { get; set; }
                      [
Indexed("Main"
, 0)]
                     
public string ProductNumber { get; set
; }
                      [
Indexed("Main"
, 1)]
                      [
Indexed("Second", direction: IndexDirection
.Ascending)]
                      [
Indexed("Third", direction: IndexDirection
.Ascending)]
                     
public string ProductName { get; set
; }
                     
public string Instructions { get; set
; }
                      [
Indexed("Third", 1, direction: IndexDirection
.Descending)]
                     
public bool IsActive { get; set
; }
                      [
Default("0"
)]
                     
public decimal? Price { get; set
; }
                      [
Default("GetDate()"
)]
                     
public DateTime? DateAdded { get; set
; }
                      [
Default("20"
)]
                     
public int Count { get; set
; }

           }
}
 

 

As you can see above, I declare a number of indexes, where index called Third has two columns – ProductName and IsActive in that exact order and different directions.  This combination will translate in the following:

CREATE NONCLUSTERED INDEX [Third] ON [dbo].[Products]

(

      [ProductName] ASC,

      [IsActive] DESC

)

 

 

 

I am trying with this implementation to get even further in eliminating a need to use scripting or separate database project to maintain the information about the database when using Code First.

Please let me know if you have any questions.

Thanks.

Post to Twitter

VS Live Orlando

I will be speaking at VS Live conference in Orlando, FL on 12/08/2011. I will be presenting the following two talks.

Working with Data on Windows Phone 7
I will talk about various approaches to work with data on Windows Phone 7. I will cover all major concepts, such as local storage, OData/WCF Data Services and custom WCF services. I will demonstrate how to retrieve data and save changes locally or to a remove web server. I will build demos for all technologies step-by-step.

You will learn:
• About options to persist the data on Windows Phone 7
• About pros and cons of each technologies
• Knowledge to build a Windows Phone application that publishes and/or consumes data

You can download the materials for this presentation here.

Using Code First (Code Only) Approach with Entity Framework
Session will include high level overview of Entity Framework and how various approaches to use it fit into application development lifecycle. Then I will build POCO classes that entity framework can use to create database as well as perform CRUD operations against the database. Various attributes that are included out of the box will be covered. This will include columns constraints, relationships, etc. I will show you how ASP.ENT MVC 3 can utilize entity framework code first metadata to build automatic validation of user input.

You will learn:
• How to build data access layer with Entity Framework Code First
• About validation approaches using POCO classes
• Fluent API and attribute based configuration option

I hope to see you there. 

Thanks.

Post to Twitter

VS Live Redmond 2011

As I mentioned before, I presented at VS Live conference in Redmond, WA yesterday, 10/20/2011.  I presented the following two talks

Working with Data on Windows Phone 7
I will talk about various approaches to work with data on Windows Phone 7.  I will cover all major concepts, such as local storage, OData/WCF Data Services and custom WCF services.  I will demonstrate how to retrieve data and save changes locally or to a remove web server.  I will build demos for all technologies step-by-step.

You will learn:
• About options to persist the data on Windows Phone 7
• About pros and cons of each technologies
• Knowledge to build a Windows Phone application that publishes and/or consumes data

You can download the materials for this presentation here.

Using Code First (Code Only) Approach with Entity Framework
Session will include high level overview of Entity Framework and how various approaches to use it fit into application development lifecycle.  Then I will build POCO classes that entity framework can use to create database as well as perform CRUD operations against the database.  Various attributes that are included out of the box will be covered.  This will include columns constraints, relationships, etc. I will show you how ASP.ENT MVC 3 can utilize entity framework code first metadata to build automatic validation of user input.
 
You will learn:
• How to build data access layer with Entity Framework Code First
• About validation approaches using POCO classes
• Fluent API and attribute based configuration option

You can download the materials for this presentation here.

Post to Twitter

Code Mastery Event

I participated in Code Mastery event yesterday.  The event was put on by my company Magenic as an all day free community training event.  It was all about CSLA.  The author if this widely used framework, Rocky Lhotka himself was in attendance.  He presented on two topics.  Yours truly spoke on CSLA and XAML technologies.  I talked about advantages on CSLA in XAML world, and documented big code savings that CSLA brings to the table.  I am planning to upload my project to CSLA web site in the next few days, as there have been some requests to show how to use CSLA in conjunction with Prism to build Silverlight or WPF applications.  I will blog once that happens, and you should be able to take advantage of that sample.  The sample is using an extensive technology stack, including Entity Framework Code First, CSLA, Prism for Silverlight, SQL Server.  You can download PowerPoint presentation here.

Thank you.

Here is the full agenda of the event.

1. CSLA .NET intro – Rocky Lhotka

Topic will give attendees a high level overview of CSLA as an application framework. Key moving parts of CSLA will be covered, along with answering the most important question: Why use CSLA? Roles of business objects, data portal, rules, authentication and authorization will be covered in principal.

2. Business object design – Eric Blackwell

Session will concentrate of best practices for designing business objects. Single responsibility principal and maintainability will be covered in light of using CSLA. Key aspects of good CSLA business layer will be covered in detail, including properties, rules, data portal, data access, business method and validation. Particular attention will be paid to structuring classes and relationship between classes. Designing based on use cases will be an important aspect of the session.

3. Business, validation, and authorization rules – Tim Price-Williams

This session will be a deep dive into the world or rules. Topics such as validation rules, user authentication and authorization will be covered. Distinction between validation and business rules be drawn. Important key scenarios will be covered, such as synchronous and asynchronous rules, client / server rules, object creation and save scenario from rules perspective. Custom and built-in rules be covered in detail. A pattern for typical business rule/methods will be illuminated.

4. Data portal and n-tier architecture – Rocky Lhotka

This topic will cover in details all possibilities that CSLA provides when abstracting communication channels between client and server components. Difference between local and remote data portal will be discussed. Various configuration patterns will be highlighted along with usage scenarios for each one. Multi-tier deployment as it relates to data portals will be covered, as well as using external data sources instead of CSLA data portal in client only scenarios.

5. Data access – Travis Brown

This session is all about data access technologies and how they relate to CSLA data portal access. The topic will include patterns for abstracting data access for business objects to promote maintainability. Discussion of Microsoft technologies for data access will take place as well.

6. XAML and MVVM – Sergey Barskiy

This session will concentrate on using CSLA as business layer in XAML based user interfaces. Taking Silverlight as an example, session will highlight how CSLA base classes can be used to facilitate communication between UI and business objects. Adaptability of CSLA business layer to seamlessly alter user interface based on rules be will covered. Patterns for wiring business objects for Silverlight environment will be part of the discussion.

7. ASP.NET MVC – Mitch Gordon

This session will concentrate on using CSLA as business layer in ASP.NET MVC based user interfaces. The discussion will include CSLA provided base classes that will allow developers write less code. The session will illuminate patters for maintaining authentication and authorization rules between server calls. Patterns for adapting UI based on user rights will be discussed.

Update 10/12/2011

Rocky wrote a blog post about the event that includes a link to a downloadable file with all the material enclosed.  You can find the blog post here.

Post to Twitter

EF Extras Project Update

Following the roadmap of my newest CodePlex project EF Code First Extras, I implemented support for default values as part of code-free migrations of SQL Server.

Default values is something that is necessary in order to support migrations.  If you are adding a new column to the table that does not allow nulls and you do not provide default value, your migration will fails.

I followed very simple code path in order to implement support.  I added default attribute to the project, and the users can simply add this new attribute to their classes in order to set default values in the database.  Attribute has two overloads – one that only takes default value as string, the other allows you to specify table and column name in addition to default value.  The reason for the second overload is the fact that some of the built-in configuration are not available to us, so if somebody changes table name via configuration, there is no way for the system to get to this information.  I do support however Table and Column attributes.

For example, let’s take a look at the following class:

    [Table("MyChair")]
   
public class Chair

    {
       
public int ChairID { get; set; }
       
public string Description { get; set
; }
 
        [
Column("ChairHeight"
)]
        [
Default("10"
)]
       
public decimal Height { get; set
; }
 
        [
Default("GetDate()"
)]
       
public DateTime DateAdded { get; set
; }
    }

 

As you see, I changed the table name, using MyChair instead of class name of Chair.  I also changed a column, using ChairHeight instead of property name of Height.  Default subsystem handles both use cases, applying the default value of 10 to the column.  As you also see, I support functions, such as GetDate(), so the newly added column DateAdded will be populated with current date/time value.  System if very flexible as you can see.  Of course, you can leave all name as is, and use much simpler code:

    public class Person
    {
       
public int PersonID { get; set; }
       
public string PersonName { get; set
; }
        [
Default("1"
)]
       
public bool IsActive { get; set
; }
        [
Default("People", "Salary", "1100"
)]
       
public decimal Salary { get; set
; }
    }

 

Above, the default for IsActive column could not be simpler.  The default for Salary column explicitly specifies table and column name for the reason I described above.

Very easy and intuitive interface, if I have to say so myself.

Please let me know your questions.  As always I appreciate any suggestions.  You can download updated source code off CodePlex site.

Post to Twitter

Update to EF Code First Extras Project

Today I issued an update to my Code Plex project that will contain a number of extras for Entity Framework Code First based applications.  You can find the project here.

I added repository project to the solution, containing base repository classes.  I had time analyze the problem some more and decided to make a few changes to the code I blogged about previously.  You can read my posts here and here.

To make the code cleaner, I decided to separate read and write patterns / code bases.  So, if someone does not like my Select implementation, you can create your own methods to select the data, but still can inherit from Write Repository to take advantage of CUD methods.

Please open unit tests project in the solution to see both select and update/inert/delete code.

Please let me know you questions, I am would like to improve my code.

Thanks.

Post to Twitter

Entity Framework Migrations

I recently posted on my intentions to create a migration solution for Entity Framework Code First using Red Gate tools.  The initial alpha version 0.9 is now live on CodePlex.  Here is how you would use the product. 

You have to obtain a license to Red Gate SQL Comparison SDK.  If you simply would like to try my solution, just get 14 days trial and check out what it does for you.  In my opinion, $700 dollars is not that much money for the functionality you get.  But of course, if you are giving your product away, that is a lot of cash.

Next you have to create some classes to use.  Your table classes are the same as in any other code first project.  You context however, now needs to inherit from ExtendedDbContext from my project.

    public class ProductsContext : ExtendedDbContext
    {
       
public ProductsContext(string connectionString)
            :
base
(connectionString)
        {
 
        }
 
       
public DbSet<Product> Products { get; set
; }
 
       
public DbSet<DbVersion> Version { get; set
; }
 
       
protected override void OnModelCreating(DbModelBuilder
modelBuilder)
        {
           
            modelBuilder.Conventions.Remove<
IncludeMetadataConvention
>();
           
base
.OnModelCreating(modelBuilder);
            
        }

 

There is one requirement, you must have a constructor that takes connection string.  You would typically have something like that anyway, so this is a minor adjustment to make.

Next you have to decide how you are going to use version comparison.  I have an interface that you must implement INewVersionProvider<TContext>.  I provide two of those out of the box, which should be enough for you to get started.  I have AssemblyBasedNewVersionProvider and ModelBasedNewVersionProvider.  Frist one stores version of the assembly that contains your DbContext and uses it for comparison.  To trigger migration you have to bump up a version of your assembly before running or deploying.  Second one uses the same mechanism as Entity Framework, creating a model hash based on actual context definition and its tables.  There is one requirement you have to use to support versioning of migrations.,  You have to include DbVersion table which is part of my framework in your context.  You can see that above in this blog in my context definition. 

Next you have to implement MigratingInitializer.  I am including base class, making this process a breeze. 


using EFUtil.Migrations.SqlServer;
using
EFUtil.Migrations;
 

namespace
EFUtil.Tests.Source
{
   
public class ProductInitializer : MigratingInitializer<ProductsContext
>
    {
       
public ProductInitializer(INewVersionProvider<ProductsContext
> versionProivider)
            :
base
(versionProivider)
        {
 
        }
 
       
protected override void BeforeMigration(ProductsContext
context)
        {
 
        }
 
       
protected override void AfterMigration(ProductsContext
context)
        {
 
        }
    }
}

 

As you can see, I provide two hooks, before and after that will allow you to massage the data before the migration or after, including adding seed data.  You can use either context or manual queries. 

using EFUtil.Migrations;
using
EFUtil.Migrations.SqlServer;
using
System.Data.Entity.Infrastructure;
 

namespace
EFUtil.TestApplication
{
   
public class ProductInitializer : MigratingInitializer<ProductsContext
>
    {
       
public ProductInitializer(INewVersionProvider<ProductsContext
> versionProivider)
            :
base
(versionProivider)
        {
 
        }
 
       
protected override void BeforeMigration(ProductsContext
context)
        {
           
var adapter = context as IObjectContextAdapter
;
           
if
(context.Database.Exists())
                adapter.ObjectContext.ExecuteStoreCommand(
"Update Products Set ProductNumber = ProductNumber + ’1′"
);
        }
 
       
protected override void AfterMigration(ProductsContext
context)
        {
           
var adapter = context as IObjectContextAdapter
;
            adapter.ObjectContext.ExecuteStoreCommand(
"Update Products Set ProductName = ProductNumber + ‘ name’"
);
        }
    }
}

 

In the example above I am firing SQL Queries, but I could have added rows to context’s tables directly and fired Save().

I am also including conventions, just like I promised.  You can read more about conventions in my posts on global conventions and attribute conventions.  I also created a follow up post here.  All the code to support conventions is now part of CodePlex project.  I felt it is necessary to formalize my efforts in order to make the functionality cleaner and include tests for it.

If you download source code, you will see unit test project.  Note: you have to run one test at a time because there is a timing issue related to dropping databases.  There is also a quick test bed project you could use to play with code.  it is called EFUtil.TestApplication.  You can just keep altering Project class and re-running the project to observe migrations in action.

This is initial version, and I already have plans to further develop the functionality.

Here is my road map for the project:

  • Publish beta releases once I have some feedback and a number of downloads without bugs reported.
  • I am planning to add
    • Index support
    • Default values support

Please let me know what you think about my efforts and provide some feedback.

Post to Twitter

Entity Framework Thoughts

I have been thinking for a little while about the future of Entity Framework, feature set on the horizon, and trying to ascertain where I would like to concentrate my next “free time” project.

If you have not been keeping up with Entity Framework, please read the last few posts on the Entity Framework design blog about the present and the future of the product.

The more I have been thinking the more I see a benefit in creating a complementary solution that would enhance features available in Entity Framework, and possibly gather some community input as to what features are most needed.  Just like a number of folks, I looked at the migrations feature outline that will likely be using existing database project API.  I worked with database projects for quite some time, and I am not a giant fan of the product.  I did submit a handful of suggested enhancements, but I am not sure now if any of them will see a light of day.  API that the project exposes is different from Visual Studio UI of course, and I am sure that API will be good to write migration code against.  On the other hand, I worked with Red Gate product called SQL Compare and related .NET SDK since about 2005 on and off.  When I used that product last, our company saved countless amounts of money by using Red Gate API to synchronize our product database with existing databases in the field.  You can read more about SQL Compare here and SDK here.  You can also buy both products as a bundle.  If you look at the price of SDK, it is about $700 per developer, and it includes 10 distribution licenses.  I encourage you to read more about licensing process and maybe even call Red Gate, if you decide to use the product.  There is also a competing product from APEX.  You can read more about that product here.

But back to Entity Framework.  I confess, I have been a fan of the product since 1.0 beta.  I used it on production projects, and I saved countless hours not having to code stored procedures and DAL layers.  I became quite excited when Code First came out on top of 4.0 version.  It offered very clean programming interface with a number of options to handle many use cases that developers might have.  It did lack a few features, namely migrations, pluggable conventions, indexes, and default values.  I have been thinking about how to address this, given that I am not a Microsoft employee.   After thinking about it for quite some time, I decided to start a CodePlex project in attempt to address these issue on my own.  I am going to rely on Red Gate based on my expedience with the product and the fact that the price is right in my opinion.

Stay tuned for the announcement.  I suspect that the initial alpha version that would include migration story will be out in a few weeks.  I am going to “productize” my blog posts on pluggable conventions and roll them into the same CodePlex project next.

I am welcoming any suggestions, including your thoughts on buying $700 product.

Thank you.

Post to Twitter

Consuming WCF REST Service from WP 7

In this post I will explore a possibility of talking to a WCF REST Service from a Windows Phone 7 device.  This should complete my posts related to consuming and working with data on Windows Phone 7.

I am going to start with creating a WCF REST Service.  First of all, I am going to create data using Entity Framework Code First.  I am going to re-use classes with my previous posts.  I am going to define a handful : Attendee, Session and Session Category.  Here is what Attendee class looks like as it will be the class I will use in my services.

using System.Collections.Generic;
using
System.ComponentModel.DataAnnotations;
 

namespace
VSLiveData.EF
{
   
public class Attendee

    {
        [
Key]
       
public int AttendeeID { get; set
; }
 
        [
StringLength(50), Required
]
       
public string FirstName { get; set
; }
 
        [
StringLength(50), Required
]
       
public string LastName { get; set
; }
 
        [
StringLength(int
.MaxValue)]
       
public string Notes { get; set
; }
 
       
public virtual ICollection<Session> Sessions { get; set
; }
    }
}

 

Nest step is to define a service.  .NET 4 comes with a template for RESTfull WCF Service, and I am going to use it to get a head start on my code.  I am going to right click on my solution, and in Add New Item dialog I will select WCF REST Service Applications.

image

In next step I will rename and update created service.  I am going to rename it to JSONDataService.  I am going to start with a method that get list of attendees sorted by last name:

 

using System.Collections.Generic;
using
System.Linq;
using
System.ServiceModel;
using
System.ServiceModel.Activation;
using
System.ServiceModel.Web;
using
VSLiveData.EF;
 

namespace
WcfRestService
{
    [
ServiceContract
]
    [
AspNetCompatibilityRequirements
(
        RequirementsMode =
AspNetCompatibilityRequirementsMode
.Allowed)]
    [
ServiceBehavior(InstanceContextMode = InstanceContextMode
.PerCall)]
   
public class JSONDataService

    {
 
        [
WebGet(UriTemplate = "/Attendee/List", ResponseFormat = WebMessageFormat.Json)]
       
public List<Attendee
> GetList()
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Configuration.LazyLoadingEnabled =
false
;
                context.Configuration.ProxyCreationEnabled =
false
;
               
return
context.Attendees.ToList();
            }
        }

 

A couple of important things to notice here.  I am turning off proxy creation.  I have to do this, otherwise I will get serialization problems.  I am also turning off lazy loading because I do not want to populate navigation properties, plus I will get an exception if I touch that property if my code is outside of using statement.  You will see that I specify uri template as well.  I want to use meaningful path for it.  I also specify JSON format for returned data.  Let’s take a look at create method next

        [WebInvoke(UriTemplate = "/Attendee/Create", Method = "POST"
            ResponseFormat =
WebMessageFormat
.Json, 
            RequestFormat =
WebMessageFormat
.Json)]
       
public Attendee Create(Attendee
attendee)
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Attendees.Add(attendee);
                context.SaveChanges();
            }
           
return
attendee;
        }

 

 

The code to actually save attendee is pretty easy – I am utilizing entity framework code first API to add new attendee to the collection, save and return new attendee.  Entity framework will populate ID for me as part of Save method.  I also specify JSON as my format for incoming and outgoing data.  The rest of the methods are very similar, so here is entire class:

using System.Collections.Generic;
using
System.Linq;
using
System.ServiceModel;
using
System.ServiceModel.Activation;
using
System.ServiceModel.Web;
using
VSLiveData.EF;
 

namespace
WcfRestService
{
    [
ServiceContract
]
    [
AspNetCompatibilityRequirements
(
        RequirementsMode =
AspNetCompatibilityRequirementsMode
.Allowed)]
    [
ServiceBehavior(InstanceContextMode = InstanceContextMode
.PerCall)]
   
public class JSONDataService

    {
 
        [
WebGet(UriTemplate = "/Attendee/List", ResponseFormat = WebMessageFormat.Json)]
       
public List<Attendee
> GetList()
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Configuration.LazyLoadingEnabled =
false
;
                context.Configuration.ProxyCreationEnabled =
false
;
               
return
context.Attendees.ToList();
            }
        }
 
        [
WebInvoke(UriTemplate = "/Attendee/Create", Method = "POST"

            ResponseFormat =
WebMessageFormat
.Json, 
            RequestFormat =
WebMessageFormat
.Json)]
       
public Attendee Create(Attendee
attendee)
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Attendees.Add(attendee);
                context.SaveChanges();
            }
           
return
attendee;
        }
 
        [
WebGet(UriTemplate = "/Attendee/Get/{id}"

            ResponseFormat =
WebMessageFormat
.Json)]
       
public Attendee Get(string
id)
        {
           
Attendee attendee = null
;
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Configuration.LazyLoadingEnabled =
false
;
                context.Configuration.ProxyCreationEnabled =
false
;
               
int attendeeID = int
.Parse(id);
                attendee = context.Attendees.Where(one => one.AttendeeID == attendeeID).FirstOrDefault();
            }
           
return
attendee;
        }
 
        [
WebInvoke(UriTemplate = "/Attendee/Update", Method = "PUT"

            ResponseFormat =
WebMessageFormat.Json, RequestFormat = WebMessageFormat
.Json)]
       
public Attendee Update(Attendee
attendee)
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Attendees.Attach(attendee);
                context.Entry(attendee).State = System.Data.
EntityState
.Modified;
                context.SaveChanges();
            }
           
return
attendee;
        }
 
        [
WebInvoke(UriTemplate = "/Attendee/Delete/{id}", Method = "DELETE"
)]
       
public void Delete(string
id)
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
               
var attendee = new Attendee() { AttendeeID = int
.Parse(id) };
                context.Attendees.Attach(attendee);
                context.Entry(attendee).State = System.Data.
EntityState
.Deleted;
                context.SaveChanges();
            }
        }
 
    }
}

 

I have to register routes for my service in Global.asax.cs file:

using System;
using
System.ServiceModel.Activation;
using
System.Web;
using
System.Web.Routing;
 

namespace
WcfRestService
{
   
public class Global : HttpApplication

    {
       
void Application_Start(object sender, EventArgs e)
        {
            RegisterRoutes();
        }
 
       
private void
RegisterRoutes()
        {
           
RouteTable.Routes.Add(new ServiceRoute("JSONDataService", new WebServiceHostFactory(), typeof(JSONDataService
)));
        }
    }
}

 

In my web.config I just need to set my connection string for my data context and specify routing engine

 

<?xml version="1.0"?>
<configuration>
 
           <connectionStrings>
                      <add
                        name="VSLive"
                        connectionString="Server=.;Database=VSLive;Trusted_Connection=True;
"
                        providerName="System.Data.SqlClient"/>

           </connectionStrings>
 
           <system.web>
                      <compilation debug="true" targetFramework="4.0" />
           </system.web>
 
           <system.webServer>
                      <modules runAllManagedModulesForAllRequests="true">
                                 <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0,

Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
                      </modules>
           </system.webServer>
 
           <system.serviceModel>
                      <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
                      <standardEndpoints>
                                 <webHttpEndpoint>
                                            <standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true"/>
                                 </webHttpEndpoint>
                      </standardEndpoints>
           </system.serviceModel>

 

 

Now, it is time to get to windows phone 7 app.  Just add new project and select Windows Phone 7 application.  The most interesting part is my view model that talks to my WCF service.  First of all, I am going to add a property to hold collection of attendees:

        public ObservableCollection<Attendee> Items { get; private set; }

 

Next, I am going to use WebClient to get the data.  I could also use HTTPRequest.  The difference between the two is that callbacks from WebClient are automatically marshaled to UI thread.  Here is how I would get the list of attendees:

        /// <summary>
       
/// Creates and adds a few ItemViewModel objects into the Items collection.
       
/// </summary>
       
public void LoadData()
        {
           
WebClient client = new WebClient
();
            client.OpenReadCompleted +=
new OpenReadCompletedEventHandler
(client_OpenReadCompleted);
            client.OpenReadAsync(
new Uri(@"http://localhost/WcfRestService/JSONDataService/Attendee/List"
));
 
   

        }
 
       
void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
           
ObservableCollection<Attendee> data = new ObservableCollection<Attendee
>();
           
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<Attendee
>));
           
List<Attendee> attendees = (List<Attendee
>)serializer.ReadObject(e.Result);
            attendees.ForEach(one => Items.Add(one));
 

        }

 

Let me explain what this code does.  I am creating a web client, then I am subscribing to completed event, then I am calling OpenRead.  Because of the URL I am using, this call will eventually end up in the method that matches my URL based on UriTemplate attribute for the method:

        [WebGet(UriTemplate = "/Attendee/List", ResponseFormat = WebMessageFormat.Json)]
       
public List<Attendee
> GetList()
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Configuration.LazyLoadingEnabled =
false
;
                context.Configuration.ProxyCreationEnabled =
false
;
               
return
context.Attendees.ToList();
            }
        }

 

In completed handler for read, I am using DataContractJsonSerializer to de-serialize downloaded data into List of attendees.  Then I am adding them to the items collection, which in turn is exposed to UI as following:

                <ListBox x:Name="FirstListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items}" >
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Margin="0,0,0,17" Width="432" Height="78">
                                <TextBlock Text="{Binding FirstName}" TextWrapping="Wrap" 
                                         
Style="{StaticResource PhoneTextExtraLargeStyle}"/>

                                <TextBlock Text="{Binding LastName}" TextWrapping="Wrap" 
                                         
Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>

                            </StackPanel>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>

 

Next, Let’s look at the Create (Insert) method, as it demonstrates how to post data to the service.

        public void OnSaveAttendee(object parameter)
        {
           
string json = null
;
           
WebClient client = new WebClient
();
            client.Headers[
"Content-Type"] = "application/json"
;
 
           
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Attendee
));
           
using (MemoryStream stream = new MemoryStream
())
            {
                serializer.WriteObject(stream, CurrentAttendee);
                stream.Flush();
                json =
Encoding.UTF8.GetString(stream.ToArray(), 0, (int
)stream.Length);
 
            }
            client.UploadStringCompleted +=
new UploadStringCompletedEventHandler
(client_UploadStringCompleted);
            client.UploadStringAsync(
new Uri("http://localhost/WcfRestService/JSONDataService/Attendee/Create"), "POST"
, json);
        }
 
       
void client_UploadStringCompleted(object sender, UploadStringCompletedEventArgs
e)
        {
           
if (e.Error == null
)
            {
               
MessageBox.Show("OK"
);
            }
           
else

            {
               
MessageBox
.Show(e.Error.Message);
            }
 
        }

 

Now, I am reversing the order of operations.  I am serializing Attendee instance to Json, then using UTF8 encoding to convert the data to a string.  One important part to remember is to set content type on the request to JSON, otherwise you will get 404 Not Found.  In completed handler I am just checking for errors.  Again, I will end up eventually in my service’s Create method based on URI Template.

You can download entire solution here.  You will also notice that even though my classes on the client, such as Attendee:

using System.Collections.Generic;
using
System.ComponentModel;
 

namespace
VSLiveData.EF
{
   
public class Attendee : INotifyPropertyChanged

    {
       
public int AttendeeID { get; set; }
 
       
public string FirstName { get; set
; }
 
       
public string LastName { get; set
; }
 
       
public string Notes { get; set
; }
 
       
public virtual ICollection<Session> Sessions { get; set
; }
 
       
public event PropertyChangedEventHandler
PropertyChanged;
 
       
private void NotifyPropertyChanged(string
propertyName)
        {
           
PropertyChangedEventHandler
handler = PropertyChanged;
           
if (null
!= handler)
            {
                handler(
this, new PropertyChangedEventArgs
(propertyName));
            }
        }
    }
}

 

I am not calling NotifyPropertyChanged anywhere.  This is because I am using NotifyPropertyChangedWeaver, which is awesome!

Thanks.

Post to Twitter

Entity Framework June CTP

Entity Framework CTP was just released.  It contains a large number of new features, including enumerations support and spatial types.  There are also important optimization improvements, such as automatically compiled queries and SQL generation improvements.  You can read more details here.

Enjoy.

Post to Twitter

Correcting Sorting Issues in Entity Framework Repository

I posted earlier on how to implement repository pattern using Entity Framework Code First, while removing a dependency on IQueryable interface.  I identified an issue that still existed in that code related to sorting.  Sorting is a tricky part because SortBy method on IQueryable needs to have two generic parameters: item type and property that the query is being sorted on.  I could not come up in that version of a generic way to do so.

I am posting a solution to the problem.  I have added new interface I am going to use for sorting:

using System;

using System.Linq;

 

namespace EFCodeFirstExtensions

{

  public interface IOrderByClause<T>

   where T : class, new()

  {

    IOrderedQueryable<T> ApplySort(IQueryable<T> query, bool firstSort);

  }

}

 

The reason I have second parameter to Apply method is that I have to use OrderBy or ThenOrderBy methods depending on where or not I already sorted a query once.  I am also moving the actual sort implementation to the method in order to support a simple implementation in the code that uses repository.  Here is my SortBy classes that implements interface above:

using System;

using System.Linq.Expressions;

using System.Reflection;

using System.Linq;

 

namespace EFCodeFirstExtensions

{

  public class OrderByClause<T, TProperty> : EFCodeFirstExtensions.IOrderByClause<T>

    where T : class, new()

  {

    private OrderByClause()

    {

 

    }

 

    public OrderByClause(

      Expression<Func<T, TProperty>> orderBy,

      SortDirection sortDirection = SortDirection.Ascending)

    {

      OrderBy = orderBy;

      SortDirection = sortDirection;

    }

 

    /// <summary>

    /// Order by expression

    /// </summary>

    private Expression<Func<T, TProperty>> OrderBy { get; set; }

 

    /// <summary>

    /// Sort direction

    /// </summary>

    private SortDirection SortDirection { get; set; }

 

    public IOrderedQueryable<T> ApplySort(IQueryable<T> query, bool firstSort)

    {

      if (SortDirection == EFCodeFirstExtensions.SortDirection.Ascending)

      {

        if (firstSort)

        {

          return query.OrderBy(OrderBy);

        }

        else

        {

          return ((IOrderedQueryable<T>)query).ThenBy(OrderBy);

        }

      }

      else

      {

        if (firstSort)

        {

          return query.OrderByDescending(OrderBy);

        }

        else

        {

          return ((IOrderedQueryable<T>)query).ThenByDescending(OrderBy);

        }

      }

 

    }

 

  }

}

 

As you can see above, my SortBy class is now responsible for applying the sort.  Now I just have to update my repository class to delegate to SortyBy:

    /// <summary>

    /// Select data from database using a where clause

    /// </summary>

    /// <typeparam name="TItem">Type of data to select</typeparam>

    /// <param name="whereClause">Where clause / function</param>

    /// <param name="orderBy">Order by clause</param>

    /// <param name="skip">Paging implementation = number of records to skip</param>

    /// <param name="top">Paging implementation = number of records to return</param>

    /// <param name="include">Navigation properties to include</param>

    /// <returns>Items selected</returns>

    public IEnumerable<TItem> Select<TItem>(

      Expression<Func<TItem, bool>> whereClause = null,

      IOrderByClause<TItem>[] orderBy = null,

      int skip = 0,

      int top = 0,

      string[] include = null)

       where TItem : class, new()

    {

 

      IQueryable<TItem> data = context.Set<TItem>();

      // handle where

      if (whereClause != null)

      {

        data = data.Where(whereClause);

      }

 

      //handle order by

      if (orderBy != null)

      {

        bool isFirstSort = true;

        orderBy.ToList().ForEach(one =>

        {

          data = one.ApplySort(data, isFirstSort);

          isFirstSort = false;

        });

      }

 

      // handle paging

      if (skip > 0)

      {

        data = data.Skip(skip);

      }

      if (top > 0)

      {

        data = data.Take(top);

      }

 

      //handle includes

      if (include != null)

      {

        include.ToList().ForEach(one => data = data.Include(one));

      }

 

      foreach (var item in data)

      {

        yield return item;

      }

    }

 

The code is very simple.  I just have to keep track of whether or not I am on the first sort by clause or not.

Here is the program that uses this method:

      using (var repo = new TestRepo())

      {

        var locs = repo.Select<Location>(one => one.LocationID == 2, new IOrderByClause<Location>[] {

          new OrderByClause<Location, int>(one=>one.LocationID, SortDirection.Descending),

          new OrderByClause<Location, string>(one=>one.LocationName, SortDirection.Ascending)}, 1, 1, new[] { "Attendees" });

 

 

        var thing = locs.ToList();

 

      }

 

As you can see, now I am not relying on IQueryable, yet I am supporting all major functions of queries against database, such as filtering, sorting, paging and including related data.

You can download complete project here.

Post to Twitter

Conclusion On Repository Pattern with Entity Framework

I have written a number of posts on this pattern lately. One thing that I used in some of them is return IQueryable. The idea behind this is to limit the number of Select methods to one in your repository. This goal is achieved by allowing calling code to append where or order by information to the return value of the repository select method. The downside of that is that you expose part of your implementation to calling code. I do not see a giant problem with this, as sometime this is a legitimate approach. Having said that, what if you would like to be more string in your data access code? This is the idea behind this post.

I am taking the approach of returning IEnumerable<T> instead. This would be pretty generic and does not reveal as much about my implementation. The rest of the CUD methods should be almost the same as in previous post. I am making a small modification to allow for deferred as well as immediate save. In an ideal world, you really should inherit from this class, so I am marking it as abstract. Now that I am returning IEnumerable, am I back in the boat of endless proliferation of Select methods? I am going to avoid this by allowing the calling code to pass in where and order by data in a generic way using Expressions. I am also going to add paging parameters as well. Sometimes you need to pass in Include information to allow passing of additional tables. If you do not want to expose that much, feel free to remove that parameter as well. Now that I know what functionality I would like to have, I am going to create an interface for my repository.

using System;

using System.Collections.Generic;

using System.Linq.Expressions;

namespace EFCodeFirstExtensions

{

public interface IEFCodeFirstRepository : IDisposable

{

/// <summary>

/// Select data from database using a where clause

/// </summary>

/// <typeparam name=”TItem”>Type of data to select</typeparam>

/// <param name=”whereClause”>Where clause / function</param>

/// <param name=”orderBy”>Order by clause</param>

/// <param name=”skip”>Paging implementation = number of records to skip</param>

/// <param name=”top”>Paging implementation = number of records to return</param>

/// <param name=”include”>Navigation properties to include</param>

/// <returns>Items selected</returns>

IEnumerable<TItem> Select<TItem>(

Expression<Func<TItem, bool>> whereClause = null,

OrderByClause<TItem>[] orderBy = null,

int skip = 0,

int top = 0,

string[] include = null)

where TItem : class, new();

/// <summary>

/// Update an item

/// </summary>

/// <typeparam name=”TItem”>Type of item to update</typeparam>

/// <param name=”item”>Item to update</param>

/// <param name=”saveImmediately”>If set to true, saved occurs right away</param>

/// <returns>Updated item</returns>

TItem Update<TItem>(TItem item, bool saveImmediately = true) where TItem : class, new();

/// <summary>

/// Delete an item

/// </summary>

/// <typeparam name=”TItem”>Type of item to delete</typeparam>

/// <param name=”saveImmediately”>If set to true, saved occurs right away</param>

/// <param name=”item”>Item to delete</param>

void Delete<TItem>(TItem item, bool saveImmediately = true) where TItem : class, new();

/// <summary>

/// Insert new item into database

/// </summary>

/// <typeparam name=”TItem”>Type of item to insert</typeparam>

/// <param name=”item”>Item to insert</param>

/// <param name=”saveImmediately”>If set to true, saved occurs right away</param>

/// <returns>Inserted item</returns>

TItem Insert<TItem>(TItem item, bool saveImmediately = true) where TItem : class, new();

/// <summary>

/// Save all pending changes

/// </summary>

void Save();

}

}

There are a couple of helper class I am using for sorting, primarily to handle sort direction in an abstract fashion.

using System;

namespace EFCodeFirstExtensions

{

public enum SortDirection

{

Ascending,

Descending

}

}

using System;

using System.Linq.Expressions;

namespace EFCodeFirstExtensions

{

public class OrderByClause<T>

where T : class, new()

{

private OrderByClause()

{

}

public OrderByClause(

Expression<Func<T, object>> orderBy,

SortDirection sortDirection = SortDirection.Ascending)

{

OrderBy = orderBy;

SortDirection = sortDirection;

}

/// <summary>

/// Order by expression

/// </summary>

public Expression<Func<T, object>> OrderBy { get; private set; }

/// <summary>

/// Sort direction

/// </summary>

public SortDirection SortDirection { get; private set; }

}

}

The implementation is very simple from a high level. I am adding a bit of protection to the update and delete methods to handle the case when entity is already in the context. I am doing this via context API for Entry method. The comment that points to this method is in green below

public TItem Update<TItem>(TItem item, bool saveImmediately = true)

where TItem : class, new()

{

DbSet<TItem> set = context.Set<TItem>();

var entry = context.Entry(item);

if (entry != null)

{

// entity is already in memory

entry.State = System.Data.EntityState.Modified;

}

else

{

set.Attach(item);

context.Entry(item).State = System.Data.EntityState.Modified;

}

if (saveImmediately)

{

context.SaveChanges();

}

return item;

}

The most interesting part is Select method. I handling all parameters in order: where, order by, etc… Since I allow nulls, I am making all parameters optional to allow selection of all rows. Here is full code for my implementation

using System;

using System.Collections.Generic;

using System.Configuration;

using System.Data.Entity;

using System.Linq;

using System.Linq.Expressions;

namespace EFCodeFirstExtensions

{

public abstract class EFCodeFirstRepository<TContext> : IDisposable, IEFCodeFirstRepository

where TContext : DbContext, new()

{

private TContext context;

/// <summary>

/// Create new instance of repository

/// </summary>

public EFCodeFirstRepository()

{

context = new TContext();

}

/// <summary>

/// Set connection string

/// </summary>

/// <param name=”connectionStringName”>Connection string name from .config file</param>

public void SetConnectionString(string connectionStringName)

{

context.Database.Connection.ConnectionString =

ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;

}

/// <summary>

/// Select data from database using a where clause

/// </summary>

/// <typeparam name=”TItem”>Type of data to select</typeparam>

/// <param name=”whereClause”>Where clause / function</param>

/// <param name=”orderBy”>Order by clause</param>

/// <param name=”skip”>Paging implementation = number of records to skip</param>

/// <param name=”top”>Paging implementation = number of records to return</param>

/// <param name=”include”>Navigation properties to include</param>

/// <returns>Items selected</returns>

public IEnumerable<TItem> Select<TItem>(

Expression<Func<TItem, bool>> whereClause = null,

OrderByClause<TItem>[] orderBy = null,

int skip = 0,

int top = 0,

string[] include = null)

where TItem : class, new()

{

IQueryable<TItem> data = context.Set<TItem>();

// handle where

if (whereClause != null)

{

data = data.Where(whereClause);

}

//handle order by

if (orderBy != null)

{

int iteration = 0;

orderBy.ToList().ForEach(one =>

{

if (iteration == 0)

{

if (one.SortDirection == SortDirection.Ascending)

{

data = data.OrderBy(one.OrderBy);

}

else

{

data = data.OrderByDescending(one.OrderBy);

}

}

else

{

if (one.SortDirection == SortDirection.Ascending)

{

data = ((IOrderedQueryable<TItem>)data).ThenBy(one.OrderBy);

}

else

{

data = ((IOrderedQueryable<TItem>)data).ThenByDescending(one.OrderBy);

}

}

iteration++;

});

}

// handle paging

if (skip > 0)

{

data = data.Skip(skip);

}

if (top > 0)

{

data = data.Take(top);

}

//handle includes

if (include != null)

{

include.ToList().ForEach(one => data = data.Include(one));

}

foreach (var item in data)

{

yield return item;

}

}

/// <summary>

/// Insert new item into database

/// </summary>

/// <typeparam name=”TItem”>Type of item to insert</typeparam>

/// <param name=”item”>Item to insert</param>

/// <param name=”saveImmediately”>If set to true, saved occurs right away</param>

/// <returns>Inserted item</returns>

public TItem Insert<TItem>(TItem item, bool saveImmediately = true)

where TItem : class, new()

{

DbSet<TItem> set = context.Set<TItem>();

set.Add(item);

if (saveImmediately)

{

context.SaveChanges();

}

return item;

}

/// <summary>

/// Update an item

/// </summary>

/// <typeparam name=”TItem”>Type of item to update</typeparam>

/// <param name=”item”>Item to update</param>

/// <param name=”saveImmediately”>If set to true, saved occurs right away</param>

/// <returns>Updated item</returns>

public TItem Update<TItem>(TItem item, bool saveImmediately = true)

where TItem : class, new()

{

DbSet<TItem> set = context.Set<TItem>();

var entry = context.Entry(item);

if (entry != null)

{

// entity is already in memory

entry.State = System.Data.EntityState.Modified;

}

else

{

set.Attach(item);

context.Entry(item).State = System.Data.EntityState.Modified;

}

if (saveImmediately)

{

context.SaveChanges();

}

return item;

}

/// <summary>

/// Delete an item

/// </summary>

/// <typeparam name=”TItem”>Type of item to delete</typeparam>

/// <param name=”saveImmediately”>If set to true, saved occurs right away</param>

/// <param name=”item”>Item to delete</param>

public void Delete<TItem>(TItem item, bool saveImmediately = true)

where TItem : class, new()

{

DbSet<TItem> set = context.Set<TItem>();

var entry = context.Entry(item);

if (entry != null)

{

// entity is already in memory

entry.State = System.Data.EntityState.Deleted;

}

else

{

set.Attach(item);

context.Entry(item).State = System.Data.EntityState.Deleted;

}

if (saveImmediately)

{

context.SaveChanges();

}

}

/// <summary>

/// Save all pending changes

/// </summary>

public void Save()

{

context.SaveChanges();

}

/// <summary>

/// Dispose context

/// </summary>

public void Dispose()

{

if (context != null)

{

context.Dispose();

}

}

}

}

As you can see, there is a variety of ways to implement the pattern, with a number of people usually defending passionately one approach or another. My, I am in a pragmatic camp, trying to get things done. Hence, feel free to use whichever version you like best.

There is one known issue with the code above. You cannot use certain types for order by clause. This is because of the issue with Expression<T, object> with cause issue with Linq trying to case something like int to object. I am going to try to find an answer to that and blog about it.

Email me any questions you might have.

Post to Twitter

CodeStock Talks

I am doing two talks at CodeStock event on Saturday, June  2011.  Tomorrow in other words Smile.

I am talking on two topics. 

Since I would like to share my slides and sample code, you can download two zip files – one for each session.  You can download each one by clicking on the title above.

Thank you.

Post to Twitter

Asynchronous Controllers Calls to Save Data in ASP.NET MVC 3

On a few occasions I wondered if it is possible to simulate Silverlight Save behavior in ASP.NET MVC.  What I mean is to asynchronously call a service from an edit form, asynchronously process the results, and update view based on saved data.  This process is a bit more complicated in ASP.NET MVC because we have to process potential errors and update UI to include errors.  Here is the workflow I am trying to implement:

Create new entry screen –> Hit Save –> Submit data to the controller –> Save data –> Return updated view –> Update UI based on updated View, including populating newly generated ID for subsequent saves.

Here is my solution outline

  • Create partial view for the form to enter data for an entity, Attendee in my case.
  • Create Controller method to accept Attendee data from UI to save
  • Return new partial view from this method
  • Push new view into DOM.

I am now going to break down my solution.  I am using the following Attendee class as the entity for entry screen.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.ComponentModel.DataAnnotations;

using MvcEFCodeFirst.Resources;

 

namespace MvcEFCodeFirst.Data

{

  public class Attendee

  {

    [Key]

    public int AttendeeID { get; set; }

 

    [StringLength(50,

      ErrorMessageResourceName = "FirstName50Chars",

      ErrorMessageResourceType = typeof(Resource))]

    [Required(

      ErrorMessageResourceName = "FirstNameRequired",

      ErrorMessageResourceType = typeof(Resource))]

    [Display(Name = "FirstName", ResourceType = typeof(Resource))]

    public string FirstName { get; set; }

 

    [StringLength(50,

      ErrorMessageResourceName = "LastName50Chars",

      ErrorMessageResourceType = typeof(Resource))]

    [Required(

      ErrorMessageResourceName = "LastNameRequired",

      ErrorMessageResourceType = typeof(Resource))]

    [Display(Name = "LastName", ResourceType = typeof(Resource))]

    public string LastName { get; set; }

 

    [StringLength(250)]

    [Required(

     ErrorMessageResourceName = "EmailRequired",

     ErrorMessageResourceType = typeof(Resource))]

    [RegularExpression(

      @"^[A-Za-z0-9](([_\.\-]?[a-zA-Z0-9]+)*)@([A-Za-z0-9]+)(([\.\-]?[a-zA-Z0-9]+)*)\.([A-Za-z]{2,})$",

      ErrorMessageResourceName = "EmaiInvalidFormat",

      ErrorMessageResourceType = typeof(Resource))]

    [Display(Name = "Email", ResourceType = typeof(Resource))]

    public string Email { get; set; }

 

    [StringLength(int.MaxValue)]

    [Display(Name = "Notes", ResourceType = typeof(Resource))]

    public string Notes { get; set; }

 

    public virtual ICollection<Session> Sessions { get; set; }

  }

}

 

Now I am going to use scaffolding to create new controller that is linked to Attendee class:  I am right-clicking on Controllers folder and selecting new Controller item

 

image

The create, display, etc… views have been created.  Now, I am going to extract form screen for Attendee edit into a partial view.  Here is what this wizard screen looks like.

image

 

The view is pretty simple, and here is what it looks like:

@model MvcEFCodeFirst.Data.Attendee

@using (Html.BeginForm(new { Id = "AttendeeForm" }))

{

  @Html.ValidationSummary(true)

  <fieldset>

    <legend>Attendee</legend>

    <div class="editor-label">

      @Html.LabelFor(model => model.FirstName)

    </div>

    <div class="editor-field">

      @Html.EditorFor(model => model.FirstName)

      @Html.ValidationMessageFor(model => model.FirstName)

    </div>

    <div class="editor-label">

      @Html.LabelFor(model => model.LastName)

    </div>

    <div class="editor-field">

      @Html.EditorFor(model => model.LastName)

      @Html.ValidationMessageFor(model => model.LastName)

    </div>

    <div class="editor-label">

      @Html.LabelFor(model => model.Email)

    </div>

    <div class="editor-field">

      @Html.EditorFor(model => model.Email)

      @Html.ValidationMessageFor(model => model.Email)

    </div>

    <div class="editor-label">

      @Html.LabelFor(model => model.Notes)

    </div>

    <div class="editor-field">

      @Html.EditorFor(model => model.Notes)

      @Html.ValidationMessageFor(model => model.Notes)

    </div>

    @if (Model.AttendeeID > 0)

    {

      @Html.HiddenFor(model => model.AttendeeID);

    }

  </fieldset>

}

 

Now, I am going to integrate this new partial view into Create/Edit shell views for Attendee.  I am going to consolidate Create and Edit views into single view.  This is more complicated now, and I am going to document the code below in more details

@if (false)

{   <script src="../../Scripts/jquery-1.5.1-vsdoc.js" type="text/javascript"></script>}

@model MvcEFCodeFirst.Data.Attendee

@{

  Layout = "~/Views/Shared/_Layout.cshtml";

}

<h2>

  @ViewBag.Title</h2>

<div id="formDiv">

  @{Html.RenderPartial("AttendeePartial", Model);}

</div>

<div>

  <button id="saveNewAttendee">

    @ViewBag.ButtonText

  </button>

</div>

<div>

  @Html.ActionLink("Back to List", "Index")

</div>

<script type="text/javascript">

  $().ready(function () {

    $(‘#saveNewAttendee’).click(function () {

      $.blockUI({ message: ‘<h1>Updating…</h1>’ });

      $.ajax({

        type: "POST",

        url: "./CreateUpdateAjax",

        data: $(‘form’).first().serialize(),

        success: function (data, status, xhr) {

          $(‘#formDiv’).html(data);

          if ($(‘#AttendeeID’).val() != undefined) {

            $(‘#saveNewAttendee’).html(‘Save’);

          };

          $.unblockUI();

        },

        error: function (xhr, status, error) {

          $.unblockUI();

          alert("error");

        }

      });

    })

 

  })

 

</script>

 

 

The top of the file is imply there to get IntelliSense for jQuery.  The next interesting code is RenderParital call.  This is only used during initial call to the view.  The form that is used for data entry is within partial view.  The last portion is javascript that is used to post the form.  First of all I need to block UI while the save is proceeding.  I downloaded and am using blockUI jQuery extension. You can download it here.  Next, I am using ajax method to submit the form data.  I am using convenient serialize method to serialize the form’s fields to be sent to the server.  I am using POST method to submit the data.  I am also specifying error and success functions.  In success function I have to first check to see if the save succeeded to create new Attendee.  I am checking this by inspecting a hidden field for Attendee ID that should have been inserted after successful save.  Then, I unblock UI.

Now, let’s see what the controller method CreateUpdateAjax looks like:

    [HttpPost]

    public ActionResult CreateUpdateAjax(Attendee attendee)

    {

      if (ModelState.IsValid)

      {

        if (attendee.AttendeeID == 0)

        {

          db.Insert(attendee);

        }

        else

        {

          db.SetModified(attendee);

          db.Save();

        }

      }

      return PartialView("AttendeePartial", attendee);

    }

 

This method is very simple.  I am relying on MVC to convert form data magically into an Attendee object.  Then I am checking for errors.  If everything succeeds, I am inserting or updating the attendee using my repository class, then returning a partial view.  I am skipping repository for now, you can read about it in my previous posts.  Just search for repository in top right corner of the blog.

In conclusion as you can see it does not take much more code to simulate Silverlight behavior in ASP.NET MVC.  Of course, if you try to create a one-page MVC application, you will find that you will need to write a lot more code.  Then again, do your users expect a single page web application?  Anyway, my goal in this post was to show how to do asynchronous saves, and I thinks this approach works pretty well.

Thanks.

Post to Twitter

More on Asynchronous Processing in ASP.NET MVC 3

In this post I would like to cover a couple of asynchronous patterns that are available in ASP.NET MVC and jQuery as it is used in MVC.

In all my previous examples related to MVC 3.0 I used regular controller class that is automatically created for a developer when New Item –> Controller is chosen from right-click menu on Controller folder in MVC application project.  Now, there is another type of controller that is available in MVC that is not often used –  AsyncControllerThis controller allows you to break your controller actions into two parts – Begin and End methods used in a typical asynchronous patter.  Just like a lot of other functionality in MVC, this pattern follows the same naming conventions.  For example, if you would like to break “Index” controller action into two methods – begin and end, you would end up with IndexAsync and IndexCompleted methods.  As a result, if you navigate to Index url, the former method will automatically be invoked, and when it flags action as completed, IndexCompleted method will be invoked.  Here is code the illustrates this point, calling database, and more specifically EF Code First, asynchronously.

  public class AttendeeController : AsyncController

  {

    private CodeStockContext db = new CodeStockContext();

 

    //

    // GET: /Attendee/

 

    public void IndexAsync()

    {

      AsyncManager.OutstandingOperations.Increment();

      BackgroundWorker worker = new BackgroundWorker();

      worker.DoWork += (o, e) =>

      {

        using (var context = new CodeStockContext())

        {

          AsyncManager.Parameters["attendees"] = context.Attendees.OrderBy(_ => _.LastName).ThenBy(_ => _.FirstName).ToList();

        }

      };

      worker.RunWorkerCompleted += (o, e) => { AsyncManager.OutstandingOperations.Decrement(); };

      worker.RunWorkerAsync();

 

    }

 

 

    public ViewResult IndexCompleted(IEnumerable<Attendee> attendees)

    {

      return View(attendees);

    }

 

As you can see, there is also parameter matching going on, where parameters of AsyncManager are automatically matched to parameters to Completed method.  The only other interesting point, is Increment and Decrement methods of AsyncManager that keep track of pending operations.  If you have multiple operations, you call increment with a parameter corresponding to a number of asynchronous operations.

Why use this pattern?  It has something to do with how IIS processes requests.  When a request comes in, IIS grabs a worker thread from the pool and processes incoming request on this thread.  If you have too many requests, IIS may run out of available threads.  So, if you have a long running IO bound operation, you can dispatch it on a background thread, thus releasing worker thread back into the IIS pool until it is needed, increasing throughput of your web site.  You can read more on this subject here.

Now, there is one more use for asynchronous processing in MVC.  I would like to demonstrate how to use ajax methods on jQuery.  You can use ajax method or post/get methods.  In my case, I am going to demonstrate how to use post method to submit a form’s data to a controller’s method without postback.  Why do this?  At the expense of complexity, you can develop a user interface very similar to windows forms interface.  So, I would likely not go this route without specific user requirements. 

So, now back to the code.  Here is what my view would look for Create action for a class called Attendee.  Frist, let me show you Attendee class:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.ComponentModel.DataAnnotations;

using MvcEFCodeFirst.Resources;

 

namespace MvcEFCodeFirst.Data

{

  public class Attendee

  {

    [Key]

    public int AttendeeID { get; set; }

 

    [StringLength(50,

      ErrorMessageResourceName = "FirstName50Chars",

      ErrorMessageResourceType = typeof(Resource))]

    [Required(

      ErrorMessageResourceName = "FirstNameRequired",

      ErrorMessageResourceType = typeof(Resource))]

    [Display(Name = "FirstName", ResourceType = typeof(Resource))]

    public string FirstName { get; set; }

 

    [StringLength(50,

      ErrorMessageResourceName = "LastName50Chars",

      ErrorMessageResourceType = typeof(Resource))]

    [Required(

      ErrorMessageResourceName = "LastNameRequired",

      ErrorMessageResourceType = typeof(Resource))]

    [Display(Name = "LastName", ResourceType = typeof(Resource))]

    public string LastName { get; set; }

 

    [StringLength(250)]

    [Required(

     ErrorMessageResourceName = "EmailRequired",

     ErrorMessageResourceType = typeof(Resource))]

    [RegularExpression(

      @"^[A-Za-z0-9](([_\.\-]?[a-zA-Z0-9]+)*)@([A-Za-z0-9]+)(([\.\-]?[a-zA-Z0-9]+)*)\.([A-Za-z]{2,})$",

      ErrorMessageResourceName = "EmaiInvalidFormat",

      ErrorMessageResourceType = typeof(Resource))]

    [Display(Name = "Email", ResourceType = typeof(Resource))]

    public string Email { get; set; }

 

    [StringLength(int.MaxValue)]

    [Display(Name = "Notes", ResourceType = typeof(Resource))]

    public string Notes { get; set; }

 

    public virtual ICollection<Session> Sessions { get; set; }

  }

}

 

Now, in my view I have regular Html form, but without submit input element:

 

@model MvcEFCodeFirst.Data.Attendee

@{

  ViewBag.Title = "Create";

  Layout = "~/Views/Shared/_Layout.cshtml";

}

<h2>

  Create</h2>

@using (Html.BeginForm())

{

  @Html.ValidationSummary(true)

  <fieldset>

    <legend>Attendee</legend>

    <div class="editor-label">

      @Html.LabelFor(model => model.FirstName)

    </div>

    <div class="editor-field">

      @Html.EditorFor(model => model.FirstName)

      @Html.ValidationMessageFor(model => model.FirstName)

    </div>

    <div class="editor-label">

      @Html.LabelFor(model => model.LastName)

    </div>

    <div class="editor-field">

      @Html.EditorFor(model => model.LastName)

      @Html.ValidationMessageFor(model => model.LastName)

    </div>

    <div class="editor-label">

      @Html.LabelFor(model => model.Email)

    </div>

    <div class="editor-field">

      @Html.EditorFor(model => model.Email)

      @Html.ValidationMessageFor(model => model.Email)

    </div>

    <div class="editor-label">

      @Html.LabelFor(model => model.Notes)

    </div>

    <div class="editor-field">

      @Html.EditorFor(model => model.Notes)

      @Html.ValidationMessageFor(model => model.Notes)

    </div>

  </fieldset>

}

<div>

  <button id="saveNewAttendee">

    Create</button>

</div>

<div>

  @Html.ActionLink("Back to List", "Index")

</div>

<script type="text/javascript">

  $().ready(function () {

    $(‘#saveNewAttendee’).click(function () {

      $.post(‘./CreateAjax’, $(‘form’).first().serialize(), function (o) {

        alert(o);

        if (o === ‘OK’)

          window.location.href = ‘./Index’;

      });

 

    })

  })

</script>

 

Now, instead of submit button, you will see a regular button with ID of saveNewAttendee.  In jQuery ready method, I am attaching a click event handler to this button, in which I am simulating the submit method.  I am calling CreateAjax method on my controller, and I am passing data array created by serializing data collected in the form.  All this is available in jQuery.  I am also passing in function that will be fired when method completes.  Here is the code for the controller method:

    [HttpPost]

    public string CreateAjax(Attendee attendee)

    {

      if (ModelState.IsValid)

      {

        db.Attendees.Add(attendee);

        db.SaveChanges();

        return "OK";

      }

 

      return string.Concat(

        ModelState.SelectMany((state) => state.Value.Errors

          .Select(e => e.ErrorMessage + Environment.NewLine)).ToArray());

    }

 

The code is pretty simple.  I am checking to make sure the model is valid, and if it is, I am saving new attendee.  Otherwise, I am create a string containing all error messages using Linq.  ModelState class contains all the validation data you could possibly need to parse the errors related to validation of your model.  It uses attributes I placed on my Attendee class to do so.  As I mentioned before, attributes are used for UI validation as well as database design when you use EF Code First with ASP.NET MVC, which is pretty cool.  If data is saved, I am returning “OK.”  As you can see in my javascript above, I am looking for string “OK” and redirecting to the Index action/Url – list of attendees.  Alternatively, I could stay on the same page.  There is a lot of room for clean up on this page, of course.  I could add some animations to play during submit, disable all the controls, save newly created ID into a hidden field for subsequent updates, show error messages, maybe even replace entire Html of the form, replacing OK string with something like return View(attendee) or RenderPartial call.

Thank you.

Post to Twitter

Localizing / Customizing Entity Framework and ASP.NET MVC 3

In most demos that you see that involve entity framework code first and ASP.NET MVC 3, localization is not mentioned.  What if you want to make your data multi-language friendly?  Here is a simple example: I want to have title column to be at most 30 characters in my entity:

    [StringLength(30)]

    public string Title { get; set; }

 

If you run the form with this configuration and you enter more than 30 characters, you will get the following message: The field Title must be a string with a maximum length of 30.  This may be OK for some folks, but it does not follow proper English grammar.  So, let’s fix the problem.  First thing we need is create a resource file.  I typically put resources into its own assembly, so I am going to create new class library project, add new item of type Resource, and create new string key Title30Characters and appropriate value:

image

Now, let’s customize the attribute in the following manner:

    [StringLength(30,

      ErrorMessageResourceName = "Title30Characters",

      ErrorMessageResourceType = typeof(Resource))]

 

That is it.  One important thing to notice is that most attributes in Data Annotations namespace have the same two parameters used for localization: ErrorMessageResourceName and ErrorMessageResourceType.

 

    [StringLength(30,

      ErrorMessageResourceName = "Title30Characters",

      ErrorMessageResourceType = typeof(Resource))]

    [Required(

      ErrorMessageResourceName = "TitleRequired",

      ErrorMessageResourceType = typeof(Resource))]

    [Display(Name = "Title", ResourceType = typeof(Resource))]

    public string Title { get; set; }

 

Above you see the final version of the Title field attributes.  I am specifying maximum length, required field and display name, all coming from resources, specifically Resource class.  One interesting thing to notice is that I am using the same attributes to define messages in ASP.NET MVC and database structure.  Database does not care about messages I am adding to StringLength attribute, but it is using the value of 30 to define the size of the field.

Now, here is one more use case:  I want to handle parsing errors.  For example I have a Session Date field that maps to date time picker control in jQuery.  If I enter the following text 112121, here is what message will be generated:  The value ’112121′ is not valid for Session Date.  Not friendly.  Here is how I can also customize all error messages in ASP.NET MVC.  I can do it in Controller (Create or Update) method.  In the example below I am using Create method, testing for errors, and putting in custom error for Session Date property:

 

    public ActionResult Create()

    {

      var view = View(new Session());

      view.ViewBag.Action = "Create";

      return view;

    }

 

   

    [HttpPost]

    public ActionResult Create(Session session)

    {

      if (ModelState.IsValid)

      {

        db.Sessions.Add(session);

        db.SaveChanges();

        return RedirectToAction("Index");

      }

      else

      {

        if (ModelState["SessionDate"].Errors.Count == 1)

        {

          string date = ModelState["SessionDate"].Value.AttemptedValue;

          DateTime test;

          if (!DateTime.TryParse(date, out test))

          {

            ModelState["SessionDate"].Errors.Clear();

            ModelState["SessionDate"].Errors.Add(new ModelError(Resource.DateInvalidInvalidFormat));

          }

        }

      }

      var view = View(session);

      view.ViewBag.Action = "Create";

      return view;

    }

 

As you can see above, I am checking for errors in ModelState, removing default error only if my parsing fails on proposed value, and putting in custom message from resources.

 

Alternatively, you can use “buddy classes” or MetadataType attribute to define your metadata in a “buddy” class.  I personally do not like this approach, it feels awkward to me.

That is all there is to it.

Thanks.

Post to Twitter

More on Repository Pattern with Entity Framework Code First

I got a comment on my first post on this pattern that pointed out unnecessary use of reflection as well as a way to make my sample cleaner.  I took an opportunity to go ahead and update the sample.  I added a bit of new functionality to illustrate how you can also pass in where clause and order by clause usage.  I added a couple of functions to my base repository class to illustrate how to do this.  Here is the function that returns filtered and sorted data:

    /// <summary>

    /// Select data from database using a where clause

    /// </summary>

    /// <typeparam name="TItem">Type of data to select</typeparam>

    /// <param name="whereClause">Where clause / function</param>

    /// <param name="orderBy">Order by clause</param>

    /// <returns></returns>

    public IOrderedQueryable<TItem> Select<TItem>(

      Expression<Func<TItem, bool>> whereClause,

      Expression<Func<TItem, object>> orderBy)

       where TItem : class, new()

    {

      IOrderedQueryable<TItem> data = context.Set<TItem>().Where(whereClause).OrderBy(orderBy);

      return data;

    }

 

 

Here is how I would call this function:

        var activeOrderedProducts =

          repository.Select<Product>(one => one.IsActive, one => one.ProducName).ToList();

 

Pretty simple so far.  Now I am going to take it a step further and extract an interface from my repository.  Ideally, I would create an interface first, but this is an experiment.  Interface would look as follows:

using System;

using System.Linq.Expressions;

using System.Linq;

using System.Data.Entity;

using System.Data.Entity.Infrastructure;

namespace RepositoryEFCodeFirst

{

  public interface IEFRepository<TContext> : IDisposable

     where TContext : DbContext, IObjectContextAdapter, new()

  {

 

    void Delete<TItem>(TItem item) where TItem : class, new();

   

    TItem Insert<TItem>(TItem item) where TItem : class, new();

   

    IQueryable<TItem> Select<TItem>() where TItem : class, new();

   

    IQueryable<TItem> Select<TItem>(Expression<Func<TItem, bool>> whereClause) where TItem : class, new();

   

    IOrderedQueryable<TItem> Select<TItem>(Expression<Func<TItem, bool>> whereClause, Expression<Func<TItem, object>> orderBy)

      where TItem : class, new();

   

    TItem Update<TItem>(TItem item) where TItem : class, new();

  }

}

 

 

The last step would be to configure dependency injection and use an interface to resolve repository.  Ordinarily, you would configure unity container in global.asax file for example for WCF service or a web application.  Code would look as following:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Microsoft.Practices.Unity;

 

namespace RepositoryEFCodeFirst

{

  class Program

  {

    static UnityContainer container = new UnityContainer();

 

    static void Main(string[] args)

    {

 

      container.RegisterType<IEFRepository<ProductContext>, EFRepository<ProductContext>>(

        new ContainerControlledLifetimeManager());

 

Now my code is even cleaner – I use interfaces everywhere and my “business code” does not deal with data access at all, considering that I would register my types elsewhere, not in my business layer.

Here is the final program code that uses repository:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Microsoft.Practices.Unity;

 

namespace RepositoryEFCodeFirst

{

  class Program

  {

    static UnityContainer container = new UnityContainer();

 

    static void Main(string[] args)

    {

 

      container.RegisterType<IEFRepository<ProductContext>, EFRepository<ProductContext>>(

        new ContainerControlledLifetimeManager());

 

      using (var repository = container.Resolve<IEFRepository<ProductContext>>())

      {

        Console.WriteLine("Total products in DB : " +

            repository.Select<Product>().Count().ToString());

 

        Product newProduct = new Product();

        newProduct.ProducName = "Plates";

        newProduct.ProducNumber = "001";

        newProduct.Notes = "SOme notes for plates";

        newProduct.IsActive = true;

 

        newProduct = repository.Insert(newProduct);

 

        var ordered = repository.Select<Product>()

          .Where(one => one.IsActive == true)

          .OrderBy(one => one.ProducNumber).ToList();

 

        Console.WriteLine("New id is " + newProduct.ProductId.ToString());

 

 

        var aProduct = repository.Select<Product>().Where(one => one.IsActive).First();

 

        var activeProducts = repository.Select<Product>(one => one.IsActive).ToList();

 

        var activeOrderedProducts =

          repository.Select<Product>(one => one.IsActive, one => one.ProducName).ToList();

 

        aProduct.ProducName = "Updated Plates";

 

        aProduct = repository.Update(aProduct);

 

        aProduct = repository.Select<Product>()

          .Where(one => one.ProductId == newProduct.ProductId).First();

 

        Console.WriteLine("Update name is: " + aProduct.ProducName.ToString());

 

        repository.Delete(aProduct);

 

      }

    }

  }

}

 

I am also pasting in entire repository class (updated):

using System;

using System.Configuration;

using System.Data.Entity;

using System.Data.Entity.Infrastructure;

using System.Linq;

using System.Linq.Expressions;

using Microsoft.Practices.Unity;

 

namespace RepositoryEFCodeFirst

{

  /// <summary>

  /// Repository base class used with DbContext

  /// </summary>

  /// <typeparam name="TContext">Type of DdContext that this repository operates on</typeparam>

  public class EFRepository<TContext> : IDisposable, IEFRepository<TContext>

      where TContext : DbContext, IObjectContextAdapter, new()

  {

    private TContext context;

 

    /// <summary>

    /// Create new instance of repository

    /// </summary>

    /// <param name="connectionStringName">Connection string name from .config file</param>

    public EFRepository(string connectionStringName)

    {

      context = new TContext();

      context.Database.Connection.ConnectionString =

          ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;

    }

 

    [InjectionConstructor]

    public EFRepository()

    {

      context = new TContext();

      context.Database.Connection.ConnectionString =

          ConfigurationManager.ConnectionStrings["ProductConnection"].ConnectionString;

    }

 

    /// <summary>

    /// Dispose repository

    /// </summary>

    public void Dispose()

    {

      if (context != null)

      {

        context.Dispose();

        context = null;

      }

    }

 

 

    /// <summary>

    /// Select data from database

    /// </summary>

    /// <typeparam name="TItem">Type of data to select</typeparam>

    /// <returns></returns>

    public IQueryable<TItem> Select<TItem>()

       where TItem : class, new()

    {

      DbSet<TItem> set = context.Set<TItem>();

      return set;

    }

 

    /// <summary>

    /// Select data from database using a where clause

    /// </summary>

    /// <typeparam name="TItem">Type of data to select</typeparam>

    /// <param name="whereClause">Where clause / function</param>

    /// <returns></returns>

    public IQueryable<TItem> Select<TItem>(Expression<Func<TItem, bool>> whereClause)

       where TItem : class, new()

    {

      IQueryable<TItem> data = context.Set<TItem>().Where(whereClause);

      return data;

    }

 

    /// <summary>

    /// Select data from database using a where clause

    /// </summary>

    /// <typeparam name="TItem">Type of data to select</typeparam>

    /// <param name="whereClause">Where clause / function</param>

    /// <param name="orderBy">Order by clause</param>

    /// <returns></returns>

    public IOrderedQueryable<TItem> Select<TItem>(

      Expression<Func<TItem, bool>> whereClause,

      Expression<Func<TItem, object>> orderBy)

       where TItem : class, new()

    {

      IOrderedQueryable<TItem> data = context.Set<TItem>().Where(whereClause).OrderBy(orderBy);

      return data;

    }

 

    /// <summary>

    /// Insert new item into database

    /// </summary>

    /// <typeparam name="TItem">Type of item to insert</typeparam>

    /// <param name="item">Item to insert</param>

    /// <returns>Inserted item</returns>

    public TItem Insert<TItem>(TItem item)

        where TItem : class, new()

    {

      DbSet<TItem> set = context.Set<TItem>();

      set.Add(item);

      context.SaveChanges();

      return item;

    }

 

    /// <summary>

    /// Update an item

    /// </summary>

    /// <typeparam name="TItem">Type of item to update</typeparam>

    /// <param name="item">Item to update</param>

    /// <returns>Updated item</returns>

    public TItem Update<TItem>(TItem item)

        where TItem : class, new()

    {

      DbSet<TItem> set = context.Set<TItem>();

      set.Attach(item);

      context.Entry(item).State = System.Data.EntityState.Modified;

      context.SaveChanges();

      return item;

    }

 

    /// <summary>

    /// Delete an item

    /// </summary>

    /// <typeparam name="TItem">Type of item to delete</typeparam>

    /// <param name="item">Item to delete</param>

    public void Delete<TItem>(TItem item)

       where TItem : class, new()

    {

      DbSet<TItem> set = context.Set<TItem>();

      var entry = context.Entry(item);

      if (entry != null)

      {

        entry.State = System.Data.EntityState.Deleted;

      }

      else

      {

        set.Attach(item);

      }

      context.Entry(item).State = System.Data.EntityState.Deleted;

      context.SaveChanges();

    }

 

  }

}

 

You can download entire solution here.

Post to Twitter

More on EF 4.1 Conventions

I got a comment today on my previous post that nullable types do not function as well.  Being a nice person that I am, I just added nullable support to sample project.

You can download update here.

Thanks.

Post to Twitter

Global Conventions in Entity Framework Code First v 4.1

In my previous post I showed how to implement custom conventions in absence of the same feature in Entity Framework 4.1.  Today I am going to expand on the same topic and try to create some global contentions.

Let me elaborate a bit on a problem I am trying to resolve.  For example, if I create a property of type decimal on a class that is used to create a set of entities in DbContext, it would result in the decimal(18,2) column definition in the database.  What if I would like my default to be (8,4) unless specified otherwise?  You can see my problem.  If I have 100 tables in my database all with 10 decimal fields, I would have to type in 1000 decimal column definitions using fluent API.   This is way too much typing to my taste. 

Here is the solution I would like to purse.  I am going to expand on my previous attribute based conventions and create a global, attribute-less convention.

First I am going to refactor my previous code and convert attribute specific conventions to generic conventions based on IConvention

Here is my new code to process all conventions and add one convention:

        /// <summary>

        /// Add one convention

        /// </summary>

        /// <param name="convention">Convention to add</param>

        protected void AddConvention(IConvention convention)

        {

            conventions.Add(convention);

        }

 

        /// <summary>

        /// Process conventions

        /// </summary>

        /// <param name="modelBuilder">Model builder</param>

        protected virtual void ProcessAddedConventions(DbModelBuilder modelBuilder)

        {

            if (conventions.Count > 0)

            {

                // poulate reflection data

                PopulateSetMetadata();

                // run through all added conventions

                conventions.ForEach(convention =>

                {

                    if (convention is IAttributeConvention)

                    {

                        ProcessAttributeBasedConvention(modelBuilder, convention as IAttributeConvention);

                    }

                   

                });

            }

        }

 

Now, I am going to write a new method to process global conventions.  I am going to extensively comment the code below:

    /// <summary>

    /// Process global conventions

    /// </summary>

    /// <param name="modelBuilder">Model builder</param>

    /// <param name="convention">One global convention to process</param>

    private void ProcessGlobalConvention(DbModelBuilder modelBuilder, IGlobalConvention convention)

    {

      var setMetadata = dbSetMetadata[this.GetType().AssemblyQualifiedName];

      // run through DbSets in current context

      setMetadata.ForEach(set =>

      {

        //run through properties in each DbSet<T> for class of type T

        set.DbSetItemProperties.ToList().ForEach(prop =>

        {

          // get type of property that matches current convention

          Type targetType = GetMatchingTypeForConfiguration(convention.PropertyConfigurationType);

          // make sure this type matched property type

          if (prop.PropertyInfo.PropertyType == targetType)

          {

            // Get entity method in ModuleBuilder

            // we are trying to get to the point of expressing the following

            //modelBuilder.Entity<Person>().Property(a => a.Name).IsMaxLength() for example

            var setMethod = modelBuilder.GetType()

                .GetMethod("Entity", BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy);

            // one we have Entity method, we have to add generic parameters to get to Entity<T>

            var genericSetMethod = setMethod.MakeGenericMethod(new Type[] { set.ItemType });

            // Get an instance of EntityTypeConfiguration<T>

            var entityInstance = genericSetMethod.Invoke(modelBuilder, null);

 

            //Get methods of EntityTypeConfiguration<T>

            var propertyAccessors = entityInstance.GetType().GetMethods(

                BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy).ToList();

 

            // we are looking for Property method that returns PropertyConfiguration

            // that is used in current convention

            var propertyMethod =

                propertyAccessors.Where(oneProperty =>

                    oneProperty.ReturnType == convention.PropertyConfigurationType).FirstOrDefault();

 

            //Get method handle in order to build the expression

            // example: (a => a.Name)

            var expressionGetMethod = GetPropertyExpressionMethodHandle();

 

            //Create lamda expression by making expression method that takes two generic parameters

            // one for class, the other for property type

            var genericExpressionMethod = expressionGetMethod

                .MakeGenericMethod(new Type[] { prop.PropertyInfo.DeclaringType, prop.PropertyInfo.PropertyType });

 

            //FInally, get lamda expression it self

            // example: (a => a.Name)

            var propertyExpression = genericExpressionMethod.Invoke(null, new object[] { prop.PropertyInfo });

 

            //Not get an instance of PrimitivePropertyConfiguration by 
            // infoking EntityTypeConfiguration<T>’s

            // Property() method

            var config = propertyMethod

                .Invoke(entityInstance, new object[] { propertyExpression }) as PrimitivePropertyConfiguration;

 

            //Finally, pass this configuration and attribute into the convention

            convention.ApplyConfiguration(prop.PropertyInfo, config);

          }

        });

      });

    }

 

Just like in attribute based convention method, I am running through all the properties for all the entities.  However, first step I am doing is making sure that the convention I am applying is matching the property type.  I am using the following method to get property type based on convention.

    /// <summary>

    /// Determine what property type should be used for a specific convention

    /// </summary>

    /// <param name="propertyConfigurationType">

    /// Type of PrimitivePropertyConfiguration to process

    /// </param>

    /// <returns>

    /// Property type that should be used with current convention

    /// </returns>

    private Type GetMatchingTypeForConfiguration(Type propertyConfigurationType)

    {

      if (propertyConfigurationType == typeof(DecimalPropertyConfiguration))

      {

        return typeof(decimal);

      }

      if (propertyConfigurationType == typeof(StringPropertyConfiguration))

      {

        return typeof(string);

      }

      if (propertyConfigurationType == typeof(DateTimePropertyConfiguration))

      {

        return typeof(DateTime);

      }

      if (propertyConfigurationType == typeof(BinaryPropertyConfiguration))

      {

        return typeof(byte[]);

      }

      else

      {

        return typeof(object);

      }

    }

 

For example, I only want to apply string based configuration to string properties.  The rest of the code on apply global conventions methods is just reflection code aimed to obtain property configuration and call Apply method of the global convention.  Here is a sample implementation for this convention, making all decimal properties decimal(8,4):

using System;

using System.Data.Entity.ModelConfiguration.Configuration;

using System.Reflection;

using EFCodeFirstConventions;

 

namespace EFCodeFirstConventionsConsole

{

  public class GenericDecimalConvention :

    GlobalConfigurationConvention<MemberInfo, DecimalPropertyConfiguration>

  {

    protected override void Apply(

      MemberInfo memberInfo,

      DecimalPropertyConfiguration propertyConfiguration)

    {

      propertyConfiguration.HasPrecision(8, 4);

    }

  }

}

 

If I add this convention to my extended context, I will make my decimals size (8,4) unless specified otherwise.  In order to do so, I am processing global conventions prior to attribute based conventions:

    /// <summary>

    /// Process conventions

    /// </summary>

    /// <param name="modelBuilder">Model builder</param>

    protected virtual void ProcessAddedConventions(DbModelBuilder modelBuilder)

    {

      if (conventions.Count > 0)

      {

        // poulate reflection data

        PopulateSetMetadata();

        // run through all global added conventions

        conventions.ForEach(convention =>

        {

          if (convention is IGlobalConvention)

          {

            ProcessGlobalConvention(modelBuilder, convention as IGlobalConvention);

          }

        });

        // run through attribute based conventions

        conventions.ForEach(convention =>

        {

          if (convention is IAttributeConvention)

          {

            ProcessAttributeBasedConvention(modelBuilder, convention as IAttributeConvention);

          }

        });

      }

    }

 

Now, let’s do another convention that is based on property names.  For example, I want to have all properties that have word Percent in them to be set as decimal(4,2).  I am just going to write a global convention for that:

using System.Data.Entity.ModelConfiguration.Configuration;

using System.Reflection;

using EFCodeFirstConventions;

 

namespace EFCodeFirstConventionsConsole

{

  public class PercentConvention :

    GlobalConfigurationConvention<MemberInfo, DecimalPropertyConfiguration>

  {

    protected override void Apply(

      MemberInfo memberInfo,

      DecimalPropertyConfiguration propertyConfiguration)

    {

      if (memberInfo.Name.ToUpper().Contains("PERCENT"))

      {

        propertyConfiguration.HasPrecision(4, 2);

      }

    }

  }

}

 

 

Super easy, now that I have my framework setup.  In this convention I am using the fact that I have MethodInfo as a parameter, so I can apply name based global conventions!  This cuts down on amount of fluent API code I have to write tremendously.  One thing to remember, I have to add conventions to my extended context in certain order to ensure they do not overwrite each other.

 

    public class CustomContext : ExtendedDbContext

    {

      public IDbSet<Person> Perosns { get; set; }

 

      protected override void AddConventions()

      {

        AddConvention(new EtendedStringConvention());

        AddConvention(new GenericDecimalConvention());

        AddConvention(new PercentConvention());

      }

 

    }

 

Here is my test Person class I am using:

using System.ComponentModel.DataAnnotations;

 

namespace EFCodeFirstConventionsConsole

{

  public class Person

  {

    [Key]

    public int PersonID { get; set; }

 

    [ExtendedString(10, 200, false)]

    public string Name { get; set; }

 

    public bool IsActive { get; set; }

 

    public decimal GenericDecimal { get; set; }

 

    public decimal Percent { get; set; }

  }

}

 

You can download updated project here.

 

Thank you.

Post to Twitter

Custom Conventions in Entity Framework Code First v 4.1

As you know, in preview version of Entity Framework code first existed concept of custom pluggable conventions that would allow the developer to avoid using large amounts of code in OnModelCreating method.  Typically, if one would like to keep entity classes free of entity framework references and possibly of Data Annotations references, fluent API available in ModelBuilder class can be used to configure entire model.  However, if you have reasonably large model, you will end up with thousands of lined of code in OnModelCreating  method of you custom DbContext.

Custom conventions would allow you to avoid this situation.  You would combine custom attributes with pluggable conventions that would pass the attribute value into your convention along with appropriate instance PropertyConfiguration, such as StringPropertyConfiguration.

Unfortunately, this functionality was removed from release candidate build and also will not be available in final build of EF 4.1 sometimes later this year.  I heard some complaints regarding this issue, and decided to write something compatible.

In this post I will describe how I went about this process, illustrating how to support primitive properties, such as string properties. 

I borrowed the concept from CTP 5.  My base class of custom convention is very similar to Microsoft one.

I started with the following interface:

using System;

using System.Data.Entity.ModelConfiguration.Configuration;

using System.Data.Entity.ModelConfiguration.Conventions;

using System.Reflection;

 

namespace EFCodeFirstConventions

{

    public interface IAttributeConvention : IConvention

    {

        void ApplyConfiguration(

            MemberInfo memberInfo,

            PrimitivePropertyConfiguration propertyConfiguration,

            Attribute attrribute);

 

        Type PropertyConfigurationType { get; }

        Type AttributeType { get; }

    }

}

 

 

IConvention class still exists in release candidate.  The idea behind the interface is as following.  I will call ApplyConfiguration method, passing the instance of attribute that my property inside entity class is decorated with along with PropertyInfo object (to provide additional information to the convention class).  Here is my implementation in an abstract class:

using System;

using System.Data.Entity.ModelConfiguration.Configuration;

using System.Reflection;

 

namespace EFCodeFirstConventions

{

    public abstract class AttributeConfigurationConvention<TMemberInfo, TPropertyConfiguration, TAttribute>

        : IAttributeConvention

        where TMemberInfo : MemberInfo

        where TPropertyConfiguration : PrimitivePropertyConfiguration

        where TAttribute : Attribute

    {

 

        public void ApplyConfiguration(

            MemberInfo memberInfo,

            PrimitivePropertyConfiguration propertyConfiguration,

            Attribute attribute)

        {

            Apply((TMemberInfo)memberInfo, (TPropertyConfiguration)propertyConfiguration, (TAttribute)attribute);

        }

 

        protected abstract void Apply(

            TMemberInfo memberInfo,

            TPropertyConfiguration propertyConfiguration,

            TAttribute attrribute);

 

 

        public Type PropertyConfigurationType

        {

            get { return typeof(TPropertyConfiguration); }

        }

 

        public Type AttributeType

        {

            get { return typeof(TAttribute); }

        }

 

    }

 

 

 

}

 

I introduced Apply method in my base convention class in order to make cleaner, strongly typed API in derived classes.  I also make convention strongly typed via generics, again in order to easy the pain of implementation.

Here is a sample implementation:

using System.Data.Entity.ModelConfiguration.Configuration;

using System.Reflection;

using EFCodeFirstConventions;

 

namespace EFCodeFirstConventionsConsole

{

    public class EtendedStringConvention :

        AttributeConfigurationConvention<MemberInfo, StringPropertyConfiguration, ExtendedStringAttribute>

    {

 

        protected override void Apply(

            MemberInfo memberInfo,

            StringPropertyConfiguration propertyConfiguration,

            ExtendedStringAttribute attrribute)

        {

            propertyConfiguration.IsUnicode(attrribute.IsUnicode);

            if (attrribute.MaxLength == int.MaxValue || attrribute.MaxLength == -1)

            {

                propertyConfiguration.IsMaxLength();

            }

            else if (attrribute.MaxLength == attrribute.MinLength && attrribute.MinLength > 0)

            {

                propertyConfiguration.IsMaxLength();

                propertyConfiguration.IsFixedLength();

                propertyConfiguration.HasMaxLength(attrribute.MaxLength);

            }

            else

            {

                propertyConfiguration.HasMaxLength(attrribute.MaxLength);

            }

        }

    }

}

 

 

As you can see, once you are in your Apply method if you have clean code that allows you to configure StringPropertyConfiguration based on ExtendedStringAttribute value.

using System;

 

namespace EFCodeFirstConventionsConsole

{

    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]

    public class ExtendedStringAttribute : Attribute

    {

        public ExtendedStringAttribute()

            : this(isUnicode: true)

        {

 

        }

 

        public ExtendedStringAttribute(

            int minLength = 0, int maxLength = int.MaxValue, bool isUnicode = true)

        {

            MinLength = minLength;

            MaxLength = maxLength;

            IsUnicode = isUnicode;

        }

 

        public int MinLength { get; private set; }

        public int MaxLength { get; private set; }

        public bool IsUnicode { get; private set; }

    }

}

 

Code above is my attribute.  I am using it as follows:

using System.ComponentModel.DataAnnotations;

 

namespace EFCodeFirstConventionsConsole

{

    public class Person

    {

        [Key]

        public int PersonID { get; set; }

 

        [ExtendedString(10, 200, false)]

 

        public string Name { get; set; }

 

        public bool IsActive { get; set; }

 

    }

}

 

Easy as pie.  Now, here is the ugly code with plenty of reflection that supports this nice feature.  I documented the class itself very thoroughly to ensure that one can understand what I wrote.

using System;

using System.Collections.Generic;

using System.Data.Entity;

using System.Data.Entity.ModelConfiguration.Configuration;

using System.Linq;

using System.Linq.Expressions;

using System.Reflection;

using EFCodeFirstConventions.Reflection;

 

namespace EFCodeFirstConventions

{

    public abstract class ExtendedDbContext : DbContext

    {

        protected override void OnModelCreating(DbModelBuilder modelBuilder)

        {

            base.OnModelCreating(modelBuilder);

            // call derived class to add conventions

            AddConventions();

            // now process conventions

            ProcessAddedConventions(modelBuilder);

        }

 

        /// <summary>

        /// Force implementation via astract class

        /// </summary>

        protected abstract void AddConventions();

 

        // conventsions saved here

        private List<IAttributeConvention> conventions = new List<IAttributeConvention>();

 

        //reflrecion data about DbContext, its sets, properties and attributes

        private static Dictionary<string, List<DbSetMetadata>> dbSetMetadata =

            new Dictionary<string, List<DbSetMetadata>>();

 

        private static object locker = new object();

 

        /// <summary>

        /// Add one convention

        /// </summary>

        /// <param name="convention">Convention to add</param>

        protected void AddConvention(IAttributeConvention convention)

        {

            conventions.Add(convention);

        }

 

        /// <summary>

        /// Process conventions

        /// </summary>

        /// <param name="modelBuilder">Model builder</param>

        protected virtual void ProcessAddedConventions(DbModelBuilder modelBuilder)

        {

            if (conventions.Count > 0)

            {

                // poulate reflection data

                PopulateSetMetadata();

                // run through all added conventions

                conventions.ForEach(convention =>

                {

                    var setMetadata = dbSetMetadata[this.GetType().AssemblyQualifiedName];

                    // run through DbSets in current context

                    setMetadata.ForEach(set =>

                        {

                            //run through properties in each DbSet<T> for class of type T

                            set.DbSetItemProperties.ToList().ForEach(prop =>

                                {

                                    // get attribute that matches convention

                                    var data = prop.DbSetItemAttributes

                                        .Where(attr => attr.Attribute.GetType() == convention.AttributeType).FirstOrDefault();

 

                                    // this class’s property has the attribute

                                    if (data != null)

                                    {

                                        // Get entity method in ModuleBuilder

                                        // we are trying to get to the point of expressing the following

                                        //modelBuilder.Entity<Person>().Property
                                        // (a => a.Name).IsMaxLength() for example

                                        var setMethod = modelBuilder.GetType()

                                            .GetMethod("Entity", BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy);

                                        // one we have Entity method, we have to add generic parameters
                                        // to get to Entity<T>

                                        var genericSetMethod = setMethod
.MakeGenericMethod(
new Type
[] { set.ItemType });

                                        // Get an instance of EntityTypeConfiguration<T>

                                        var entityInstance = genericSetMethod
Invoke(modelBuilder,
null
);

 

                                        //Get methods of EntityTypeConfiguration<T>

                                        var propertyAccessors = entityInstance.GetType().GetMethods(

                                            BindingFlags.Public | BindingFlags.Instance 
|
BindingFlags
.FlattenHierarchy).ToList();

 

                                        // we are looking for Property method that returns 
                                        // PropertyConfiguration

                                        // that is used in current convention

                                        var propertyMethod =

                                            propertyAccessors.Where(oneProperty =>

                                                oneProperty.ReturnType == 
.PropertyConfigurationType).FirstOrDefault();

 

                                        //Get method handle in order to build the expression

                                        // example: (a => a.Name)

                                        var expressionGetMethod = 
GetPropertyExpressionMethodHandle();

 

                                        //Create lamda expression by making expression method that takes two generic parameters

                                        // one for class, the other for property type

                                        var genericExpressionMethod = expressionGetMethod

                                            .MakeGenericMethod(new Type[] { prop.PropertyInfo.DeclaringType, prop.PropertyInfo.PropertyType });

 

                                        //FInally, get lamda expression it self

                                        // example: (a => a.Name)

                                        var propertyExpression = 
genericExpressionMethod.Invoke(
null, new object
[] { prop.PropertyInfo });

 

                                        //Not get an instance of PrimitivePropertyConfiguration by 
                                        //infoking EntityTypeConfiguration<T>’s

                                        // Property() method

                                        var config = propertyMethod

                                            .Invoke(entityInstance, 
new object[] { propertyExpression }) as PrimitivePropertyConfiguration;

 

                                        //Finally, pass this configuration and attribute into the 
                                        // convention

                                        convention.ApplyConfiguration(prop.PropertyInfo, config, data.Attribute);

                                    }

 

                                });

                        });

                });

            }

        }

 

        /// <summary>

        /// Locate member info handle for GetPropertyExpression method by iterating through

        /// class hierarchy

        /// </summary>

        /// <returns>MemberInfo handle for GetPropertyExpression method</returns>

        private MethodInfo GetPropertyExpressionMethodHandle()

        {

            MethodInfo returnValue = null;

            Type currentType = this.GetType();

            while (returnValue == null)

            {

                returnValue = currentType

                                .GetMethod("GetPropertyExpression",

                                BindingFlags.NonPublic | BindingFlags.FlattenHierarchy 
|
BindingFlags
.Static);

                if (returnValue == null)

                {

                    currentType = currentType.BaseType;

                    if (currentType == null)

                    {

                        break;

                    }

                }

            }

            return returnValue;

        }

 

        /// <summary>

        /// Create Expression that can access property on a class.  You would typically write it as

        /// (p=>p.Name)

        /// In our case we are using Expression to build the same expression

        /// </summary>

        /// <typeparam name="TClass">Class type that is owning the property in question</typeparam>

        /// <typeparam name="TProperty">Property type</typeparam>

        /// <param name="property">PropertyInfo object for property in question</param>

        /// <returns>Expression that returns the property, such as (p=>p.Name)</returns>

        private static Expression<Func<TClass, TProperty>> GetPropertyExpression<TClass, TProperty>(PropertyInfo property)

        {

            //  Create {p=> portion of the Epxression in example (p=>p.Name)

            var objectExpression = Expression.Parameter(property.DeclaringType, "param");

            // create property expression – .Name for example

            var propertyExpression = Expression.Property(objectExpression, property);

            //Create lambda expression from two parts

            var returnValue = Expression.Lambda<Func<TClass, TProperty>>(propertyExpression, objectExpression);

            return returnValue;

        }

 

        /// <summary>

        /// RUn through DbContnxt sets and save reflection data in a dictionary

        /// </summary>

        private void PopulateSetMetadata()

        {

            if (!dbSetMetadata.ContainsKey(this.GetType().AssemblyQualifiedName))

            {

                lock (locker)

                {

                    if (!dbSetMetadata.ContainsKey(this.GetType().AssemblyQualifiedName))

                    {

                        var props = this.GetType().GetProperties(

                            BindingFlags.Public | BindingFlags.Instance | 
BindingFlags
.FlattenHierarchy).ToList();

                        List<DbSetMetadata> sets = new List<DbSetMetadata>();

                        props.ForEach(one =>

                        {

                            //Filter out db sets

                            if (one.PropertyType.IsGenericType &&

                                (one.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>) ||

                                one.PropertyType.GetGenericTypeDefinition() == typeof(IDbSet<>)))

                            {

                                sets.Add(new DbSetMetadata(one.PropertyType.GetGenericArguments().First(), one));

                            }

                        });

                        // add this context to diutionary

                        dbSetMetadata.Add(this.GetType().AssemblyQualifiedName, sets);

                    }

                }

            }

        }

    }

}

 

That is all.  Feel free to use the code.  Please contact me (use Contact page) if you would like me to create CodePlex project for this sample of extend it further.

Here is what my inherited sample DbContext looks like:

        public class CustomContext: ExtendedDbContext

        {

            public IDbSet<Person> Perosns { get; set; }

 

            protected override void AddConventions()

            {

                AddConvention(new EtendedStringConvention());

            }

 

        }

 

 

You can download full project here.

Thanks.

Post to Twitter

Entity Framework Code First Caching

As I was playing around with Entity Framework code first and ASP.NET MVC, it became pretty obvious that caching of some of the EF query results would be pretty handy.  For example, if you look at my post that includes a simple ASP.NET MVC blogging application, you could see that I have to keep fetching the list of categories every time I render the blog entry screen.  This is because I want to keep my application stateless.  This is not very efficient.

As a result, I looked around for some caching options.  There is a second-level cache project that was published on Microsoft code.  Here is the link to it.  This is very involved and handy project, but currently does not support EF 4.1 (official release name for a number of features, including Code First).  You can download release candidate here or get it from NuGet inside Visual Studio 2010.

Also, I wanted something more explicit, such as extension method to specify that I want to cache results of a specific query.  Here is how I wrote a simple extension method:

        public static IEnumerable<T> AsCacheable<T>(this IQueryable<T> query)

        {

            if (cacheProvider == null)

            {

                throw new InvalidOperationException("Please set cache provider (call SetCacheProvider) before using caching");

            }

            return cacheProvider.GetOrCreateCache<T>(query);

        }

 

I envision my final usage of new functionality will look a following:

 

EFCacheExtensions.SetCacheProvider(MemoryCacheProvider.GetInstance());

using (ProductContext context = new ProductContext())

{

  var query = context.Products.OrderBy(one => one.ProductNumber).
    Where(one => one.IsActive).AsCacheable();

 

}

 

In the example above, I am using in-memory cache provider I wrote.  This provider is using static memory variable to cache data.  This is poor man’s caching solution every day.  To elaborate, this approach works in any environment.  If you are using think client, such as WPF or Windows forms, the cache will stay in memory as long as the application is running.  This is because of the rule of garbage collector.  Static variables are never garbage collected.  In case of web application, such as WCF, the static variables will leave as long as application pool lives.  They will be lost when application pool is recycled.  Default time for app pool recycling in IIS 7 is 20 minutes.  This means that your cache will not live very long.  So, I am also going to implement a provider that is using AppFabric Caching (formerly known as project Velocity).

Since I would like to have an abstraction over both, so that I do not have to change the code going from Velocity to In-Memory provider, I will create an interface to deal with that.

    public interface IEFCacheProvider

    {

        IEnumerable<T> GetOrCreateCache<T>(IQueryable<T> query);

        IEnumerable<T> GetOrCreateCache<T>(IQueryable<T> query, TimeSpan cacheDuration);

        bool RemoveFromCache<T>(IQueryable<T> query);

    }

 

Now, the key code is to implement both providers.  I am going to explain memory provider first.  Here is the class

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Collections.Concurrent;

 

namespace EFCodeFirstCacheExtensions

{

    public class MemoryCacheProvider : IEFCacheProvider

    {

        private MemoryCacheProvider() { }

 

        public static MemoryCacheProvider GetInstance()

        {

            lock (locker)

            {

                if (dictionary == null)

                {

                    dictionary = new ConcurrentDictionary<string, CacheItem>();

                }

 

                if (instance == null)

                {

                    instance = new MemoryCacheProvider();

                }

            }

            return instance;

        }

 

        private static ConcurrentDictionary<string, CacheItem> dictionary;

        private static MemoryCacheProvider instance;

        private static object locker = new object();

 

        public IEnumerable<T> GetOrCreateCache<T>(IQueryable<T> query, TimeSpan cacheDuration)

        {

            string key = GetKey<T>(query);

 

            CacheItem item = dictionary.GetOrAdd(

                key,

                (keyToFind) => { return new CacheItem()

                    { Item = query.ToList(), AdditionTime = DateTime.Now }; });

 

            if (DateTime.Now.Subtract(item.AdditionTime) > cacheDuration)

            {

                item = dictionary.AddOrUpdate(

                    key,

                    new CacheItem() { Item = item.Item, AdditionTime = DateTime.Now },

                    (keyToFind, oldItem) => { return new CacheItem()

                        { Item = query.ToList(), AdditionTime = DateTime.Now }; });

            }

            foreach (var oneItem in ((List<T>)item.Item))

            {

                yield return oneItem;

            }

        }

 

        public IEnumerable<T> GetOrCreateCache<T>(IQueryable<T> query)

        {

            string key = GetKey<T>(query);

 

            CacheItem item = dictionary.GetOrAdd(

                key,

                (keyToFind) => { return new CacheItem()

                    { Item = query.ToList(), AdditionTime = DateTime.Now }; });

 

            foreach (var oneItem in ((List<T>)item.Item))

            {

                yield return oneItem;

            }

        }

 

        public bool RemoveFromCache<T>(IQueryable<T> query)

        {

            string key = GetKey<T>(query);

            CacheItem item = null;

            return dictionary.TryRemove(key, out item);

        }

 

        private static string GetKey<T>(IQueryable<T> query)

        {

            string key = string.Concat(query.ToString(), "\n\r",

                typeof(T).AssemblyQualifiedName);

            return key;

        }

    }

}

 

 

As you can see, I am implementing the original provider interface.  I am supporting self-expiring as well as non-expiring cache.  I am using a neat feature of EF Code Frist.  If I issue to .ToString() of IQueryable, I will get the actual T-SQL query that will be executed.  I am using it as a key for caching in conjunction with class name (T is the type that is returned by they query).  I have to issue ToList prior to caching because of deferred execution in Entity Framework – query is not executed on the back end until I access at least one result.  So, am caching the results of the query as List<T>, but returning IEnumerable<T> to be more generic.

Next, comes AppFabric provider.  The only difference is that I am using AppFabric caching features.  To write and to test, I have to install AppFabric locally and add references to client DLLs to my project.  Those DLLs are:

Microsoft.ApplicationServer.Caching.Client

Microsoft.ApplicationServer.Caching.Core

Once those are done, I just need to replace any chunks of code that refer to memory to refer to cache object from AppFabric.  Here is the full class:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using EFCodeFirstCacheExtensions;

using Microsoft.ApplicationServer.Caching;

 

namespace AppFabricCacheProvider

{

    public class AppFabricCacheProvider : IEFCacheProvider

    {

        private AppFabricCacheProvider() { }

 

        private static object locker = new object();

        private static AppFabricCacheProvider instance;

        private static DataCache cache;

 

        public static AppFabricCacheProvider GetInstance()

        {

            lock (locker)

            {

                if (instance == null)

                {

                    instance = new AppFabricCacheProvider();

                    DataCacheFactory factory = new DataCacheFactory();

                    cache = factory.GetCache("Default");

                }

            }

            return instance;

        }

        public IEnumerable<T> GetOrCreateCache<T>(IQueryable<T> query, TimeSpan cacheDuration)

        {

            string key = GetKey<T>(query);

 

            var cacheItem = cache.Get(key);

            if (cacheItem == null)

            {

                cache.Put(key, query.ToList(), cacheDuration);

                foreach (var oneItem in query)

                {

                    yield return oneItem;

                }

            }

            else

            {

                foreach (var oneItem in ((List<T>)cacheItem))

                {

                    yield return oneItem;

                }

            }

        }

 

        public IEnumerable<T> GetOrCreateCache<T>(IQueryable<T> query)

        {

            string key = GetKey<T>(query);

 

            var cacheItem = cache.Get(key);

            if (cacheItem == null)

            {

                cache.Put(key, query.ToList());

                foreach (var oneItem in query)

                {

                    yield return oneItem;

                }

            }

            else

            {

                foreach (var oneItem in ((List<T>)cacheItem))

                {

                    yield return oneItem;

                }

            }

        }

 

        public bool RemoveFromCache<T>(IQueryable<T> query)

        {

            string key = GetKey<T>(query);

            CacheItem item = null;

            return cache.Remove(key);

        }

 

        private static string GetKey<T>(IQueryable<T> query)

        {

            string key = string.Concat(query.ToString(), "\n\r",

                typeof(T).AssemblyQualifiedName);

            return key;

        }

    }

}

 

II am using built-in expiration as well instead of computing the expiration myself.  I am using DataCacheFactory to create an instance of cache named Default.  Here is my app.config from my unit test project that supports this code:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

    <!–configSections must be the FIRST element –>

    <configSections>

        <section name="dataCacheClient"

           type="Microsoft.ApplicationServer.Caching.DataCacheClientSection, 
Microsoft.ApplicationServer.Caching.Core, Version=1.0.0.0, 
Culture=neutral, PublicKeyToken=31bf3856ad364e35
"

           allowLocation="true"

           allowDefinition="Everywhere"/>

    </configSections>

 

    <dataCacheClient>

        <hosts>

            <host

               name="SERGEYB-PC1"

               cachePort="22233"/>

        </hosts>

        <localCache

             isEnabled="true"

             sync="TimeoutBased"

             objectCount="100000"

             ttlValue="300" />

 

    </dataCacheClient>

 

    <connectionStrings>

        <add name="ProductConnection"

             connectionString="Server=(local);Database=Products;Trusted_Connection=True;"

             providerName="System.Data.SqlClient"/>

    </connectionStrings>

 

</configuration>

 

Also, I used AppFabric console to create cache named Default.

Here is my unit test code that test usage of my new classes:

        [TestMethod]

        public void MemoryCacheProviderGetOrCreateCacheUsageTest()

        {

            EFCacheExtensions.SetCacheProvider(MemoryCacheProvider.GetInstance());

            using (ProductContext context = new ProductContext())

            {

                var query = context.Products

                    .OrderBy(one => one.ProductNumber)

                    .Where(one => one.IsActive).AsCacheable();

 

                Assert.AreEqual(2, query.Count(), "Should have 2 rows");

 

                SQLCommandHelper.ExecuteNonQuery("Update Products Set IsActive = 0");

 

                query = context.Products

                    .OrderBy(one => one.ProductNumber)

                    .Where(one => one.IsActive).AsCacheable();

                Assert.AreEqual(2, query.Count(), "Should have 2 rows");

 

 

                IQueryable<Product> cleanupQuery = context.Products

                    .OrderBy(one => one.ProductNumber)

                    .Where(one => one.IsActive);

 

                EFCacheExtensions.RemoveFromCache<Product>(cleanupQuery);

 

                query = context.Products

                    .OrderBy(one => one.ProductNumber)

                    .Where(one => one.IsActive).AsCacheable();

                Assert.AreEqual(0, query.Count(), "Should have 0 rows");

 

                EFCacheExtensions.RemoveFromCache<Product>(cleanupQuery);

            }

 

        }

 

This demonstrates my intended use of caching in c – simply add AsCacheable to explicitly cache results of a query.  You can also supply timespan for which the cache will live.

You can download entire solution with unit tests and In-Memory and AppFabric implementations here.

Thanks.

Post to Twitter

Repository Pattern with Entity Framework

Repository pattern is a popular architecture pattern that is used to create data access code / layer for an application.  Basic principal behind the pattern is that business object in your application never talks to database directly, but instead talks to repository that takes POCO classes and also returns POCO classes as results of a query.  This way your business layer does not take on a dependency on a specific database or data access layer implementation.  As we see from experience, data access technology does not see to be handing around for very long.

As I was working on entity framework code first, I decided to take a few minutes to develop a number of  convenience classes that would make it easier to repositories that internally use entity framework code first.  Typically, you would create a repository for a set of classes, and this repository will be responsible for querying some data as well as CUD operations.  For example, if you had a product table, you might have repository with methods such as CreateProduct(Product product), UpdateProduct(Product product), DeleteProduct(Product product), GetProductsOrderedByName(int pageNumber, int rowsPerPage), GetProductsOrderedByNumber(int pageNumber, int rowsPerPage), etc…  As you develop more of your application, you might end up with a whole number of repositories.  A lot of them might have similar or the same methods.

I would like to simplify this approach by creating a generic repository that works with DbContext.  So, I am going to create a generic repository for  context type.

  /// <summary>

    /// Repository base class used with DbContext

    /// </summary>

    /// <typeparam name="TContext">Type of DdContext that this repositiory operates on</typeparam>

    public class EFRepository<TContext> : IDisposable

        where TContext : DbContext, IObjectContextAdapter, new()

    {

        private TContext context;

 

        private EFRepository()

        {

 

        }

        /// <summary>

        /// Create new instance of repository

        /// </summary>

        /// <param name="connecstionStringName">Connection string name from .config file</param>

        public EFRepository(string connecstionStringName)

        {

            context = new TContext();

            context.Database.Connection.ConnectionString =

                ConfigurationManager.ConnectionStrings[connecstionStringName].ConnectionString;

        }

 

        /// <summary>

        /// Dipose repository

        /// </summary>

        public void Dispose()

        {

            if (context != null)

            {

                context.Dispose();

                context = null;

            }

        }

 

As you can see, I am using DbContext as a parameter.  I also force to user to supply connection string.  In constructor I am creating new instance of the context.  As a good little developer, I am using IDisposable interface to dispose of the context.  So far pretty simple.  Next, I would like to write generic query mechanism via Select method.

 

 

        /// <summary>

        /// Select data from database

        /// </summary>

        /// <typeparam name="TItem">Type of data to select</typeparam>

        /// <returns></returns>

        public IQueryable<TItem> Select<TItem>()

           where TItem : class, new()

        {

            PropertyInfo property = GetDbSet(typeof(TItem));

 

            DbSet<TItem> set = property.GetValue(context, null) as DbSet<TItem>;

 

            return set;

        }

 
        private PropertyInfo GetDbSet(Type itemType)
        {
            var properties = typeof(TContext).GetProperties().

Where(item => item.PropertyType.Equals(typeof(DbSet<>).MakeGenericType(itemType)));
 
            return properties.First();
        }

 

My select method returns IQueryable.  This way the user of the repository can supply strongly types where and order by clauses as well as Top() and Skip() methods for paging.  Here is an example:

using (EFRepository<ProductContext> repository = new EFRepository<ProductContext>("ProductConnection"))

            {

 

                var ordered = repository.Select<Product>().Where(one => one.IsActive == true).OrderBy(one => one.ProducNumber).ToList();

 

This way I can avoid a whole slew of Select methods and the only dependency I take on is IQueryable, which is a generic interface.in System.Linq namespace located in System.Core.  This to me is a small price to pay for code reduction in repository. 

Next, insert code.  This is super simple of course. 

        /// <summary>

        /// Insert new item into database

        /// </summary>

        /// <typeparam name="TItem">Type of item to insert</typeparam>

        /// <param name="item">Item to insert</param>

        /// <returns>Inserted item</returns>

        public TItem Insert<TItem>(TItem item)

            where TItem : class, new()

        {

            DbSet<TItem> set = GetDbSet(typeof(TItem)).GetValue(context, null) as DbSet<TItem>;

            set.Add(item);

            context.SaveChanges();

            return item;

        }

 

Again, I am using a bit of reflection to find the property DbSet property in the context.  Once I find the set, I add new item to it, fire Save and return new item.  I am using Identity field, and conveniently enough returned item will have the value populated.

Here is an update method:

        /// <summary>

        /// Update na item

        /// </summary>

        /// <typeparam name="TItem">Type of item to update</typeparam>

        /// <param name="item">Item to update</param>

        /// <returns>Updated item</returns>

        public TItem Update<TItem>(TItem item)

            where TItem : class, new()

        {

            DbSet<TItem> set = GetDbSet(typeof(TItem)).GetValue(context, null) as DbSet<TItem>;

            set.Attach(item);

            context.Entry(item).State = System.Data.EntityState.Modified;

            context.SaveChanges();

            return item;

        }

 

Update code is only slightly more complicated.  I am simply setting the state to modified after I am attaching the item in order to force the update.  Delete statement is about the same:

 

 

 

        /// <summary>

        /// Delete an item

        /// </summary>

        /// <typeparam name="TItem">Type of item to delete</typeparam>

        /// <param name="item">Item to delete</param>

        public void Delete<TItem>(TItem item)

           where TItem : class, new()

        {

            DbSet<TItem> set = GetDbSet(typeof(TItem)).GetValue(context, null) as DbSet<TItem>;

            var entry = context.Entry(item);

            if (entry != null)

            {

                entry.State = System.Data.EntityState.Deleted;

            }

            else

            {

                set.Attach(item);

            }

            context.Entry(item).State = System.Data.EntityState.Deleted;

            context.SaveChanges();

        }

The only difference is that I am testing for entity not being in the context, which is really should not be necessary ordinarily, but I ran into an issue like this in my test project, so I added this code to it.

That is all there is to it.  Here is the full class code:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Data.Entity;

using System.Linq.Expressions;

using System.Reflection;

using System.Configuration;

using System.Data.Entity.Infrastructure;

using System.Data.Objects;

 

namespace RepositoryEFCodeFirst

{

    /// <summary>

    /// Repository base class used with DbContext

    /// </summary>

    /// <typeparam name="TContext">Type of DdContext that this repositiory operates on</typeparam>

    public class EFRepository<TContext> : IDisposable

        where TContext : DbContext, IObjectContextAdapter, new()

    {

        private TContext context;

 

        private EFRepository()

        {

 

        }

        /// <summary>

        /// Create new instance of repository

        /// </summary>

        /// <param name="connecstionStringName">Connection string name from .config file</param>

        public EFRepository(string connecstionStringName)

        {

            context = new TContext();

            context.Database.Connection.ConnectionString =

                ConfigurationManager.ConnectionStrings[connecstionStringName].ConnectionString;

        }

 

        /// <summary>

        /// Dipose repository

        /// </summary>

        public void Dispose()

        {

            if (context != null)

            {

                context.Dispose();

                context = null;

            }

        }

 

 

        /// <summary>

        /// Select data from database

        /// </summary>

        /// <typeparam name="TItem">Type of data to select</typeparam>

        /// <returns></returns>

        public IQueryable<TItem> Select<TItem>()

           where TItem : class, new()

        {

            PropertyInfo property = GetDbSet(typeof(TItem));

 

            DbSet<TItem> set = property.GetValue(context, null) as DbSet<TItem>;

 

            return set;

        }

 

        /// <summary>

        /// Insert new item into database

        /// </summary>

        /// <typeparam name="TItem">Type of item to insert</typeparam>

        /// <param name="item">Item to insert</param>

        /// <returns>Inserted item</returns>

        public TItem Insert<TItem>(TItem item)

            where TItem : class, new()

        {

            DbSet<TItem> set = GetDbSet(typeof(TItem)).GetValue(context, null) as DbSet<TItem>;

            set.Add(item);

            context.SaveChanges();

            return item;

        }

 

        /// <summary>

        /// Update na item

        /// </summary>

        /// <typeparam name="TItem">Type of item to update</typeparam>

        /// <param name="item">Item to update</param>

        /// <returns>Updated item</returns>

        public TItem Update<TItem>(TItem item)

            where TItem : class, new()

        {

            DbSet<TItem> set = GetDbSet(typeof(TItem)).GetValue(context, null) as DbSet<TItem>;

            set.Attach(item);

            context.Entry(item).State = System.Data.EntityState.Modified;

            context.SaveChanges();

            return item;

        }

 

        /// <summary>

        /// Delete an item

        /// </summary>

        /// <typeparam name="TItem">Type of item to delete</typeparam>

        /// <param name="item">Item to delete</param>

        public void Delete<TItem>(TItem item)

           where TItem : class, new()

        {

            DbSet<TItem> set = GetDbSet(typeof(TItem)).GetValue(context, null) as DbSet<TItem>;

            var entry = context.Entry(item);

            if (entry != null)

            {

                entry.State = System.Data.EntityState.Deleted;

            }

            else

            {

                set.Attach(item);

            }

            context.Entry(item).State = System.Data.EntityState.Deleted;

            context.SaveChanges();

        }

 

        private PropertyInfo GetDbSet(Type itemType)

        {

            var properties = typeof(TContext).GetProperties().Where(item => item.PropertyType.Equals(typeof(DbSet<>).MakeGenericType(itemType)));

 

            return properties.First();

        }

 

    }

}

 

Here is sample code that uses this repository:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace RepositoryEFCodeFirst

{

    class Program

    {

        static void Main(string[] args)

        {

            using (EFRepository<ProductContext> repository = new EFRepository<ProductContext>("ProductConnection"))

            {

                Console.WriteLine("Total products in DB : " +

                    repository.Select<Product>().Count().ToString());

 

                Product newProduct = new Product();

                newProduct.ProducName = "Plates";

                newProduct.ProducNumber = "001";

                newProduct.Notes = "SOme notes for plates";

                newProduct.IsActive = true;

 

                newProduct = repository.Insert<Product>(newProduct);

 

                var ordered = repository.Select<Product>().Where(one => one.IsActive == true).OrderBy(one => one.ProducNumber).ToList();

 

                Console.WriteLine("New id is " + newProduct.ProductId.ToString());

 

 

                var aProduct = repository.Select<Product>().Where(one => one.IsActive).First();

                aProduct.ProducName = "Updated Plates";

 

                aProduct = repository.Update<Product>(aProduct);

 

                aProduct = repository.Select<Product>().Where(one => one.ProductId == newProduct.ProductId).First();

                Console.WriteLine("Update name is: " + aProduct.ProducName.ToString());

 

                repository.Delete<Product>(aProduct);

 

            }

        }

    }

}

 

I captured the result of the query (in bold) in profiler of my select with where and order by to ensure the operation takes place on the server.  Here is the query.

SELECT

[Extent1].[ProductId] AS [ProductId],

[Extent1].[ProducNumber] AS [ProducNumber],

[Extent1].[ProducName] AS [ProducName],

[Extent1].[Notes] AS [Notes],

[Extent1].[IsActive] AS [IsActive]

FROM [dbo].[Products] AS [Extent1]

WHERE 1 = [Extent1].[IsActive]

ORDER BY [Extent1].[ProducNumber] ASC

This concludes sample repository pattern implementation for Entity Framework Code First.  On a side note, I have not been blogging quite as much.  As I found out, spending 2-3 hours in the car every day going to/from work is not very conducive to blogging Smile.

Thanks.

Post to Twitter

Working with Data on Windows Phone 7 – Part 2

In this part I am going to use WCF Data Services (formerly known as project Astoria and ADO.NET Data Services) to accomplish the same couple of tasks I did in WCF custom service.  I am going to get a list of people and add a person.

I will use exact same project as I did the last time.  As you recall, I created a database with one table using EF Code First.  This is where I am going to start.  In first step I am going to create an Entity Framework model from that database.  To do so, I am going to add new item to my web project and select Entity Framework model.

image

I will then walk through EF model wizard to generate the model from my database:

image

image

 

image

This will generate my model with my person class.

WCF Data Service will expose my model via web RESTful interfaces.  To add the service, I am going to add new item again, but now select WCF Data Service as item type:

 

image

Next step is to configure WCF Data Service to use my entity model.  This step is pretty easy, since service is a generic type with a parameter that takes entity model

    public class PersonWcfDataService : DataService<PersonsDbEntities>
    {
       
public static void InitializeService(DataServiceConfiguration
config)
        {
            config.SetEntitySetAccessRule(
"*", EntitySetRights
.All);
            config.DataServiceBehavior.MaxProtocolVersion =
DataServiceProtocolVersion.V2;
        }
    }

 

In the code above I am setting rights to all entities to everyone.  In production I would not do this, but it works as illustration.  In my next step I am going to test the service.  I am going to right click on PersonWcfDataService.svc file that was generated in the step above and select View In Browser.

image

Next, I want to make sure I can get the list of people.  I am going to change my Url and test that.  You can see the address and result below:

image

Of course the results look like Atom feed since OData that WCF Data Service implement extends AtomPub protocol.  I can look at the data by selecting view source.  The data looks as following:

image

Next I need to generate proxy for my Phone application.  Unfortunately, add service reference does not work for phone Silverlight applications.  So, I am going to download necessary files from CodePlex to proceed.

Visit http://odata.codeplex.com and download ODataClient_BinariesAndCodeGenToolForWinPhone.zip.  Once it is on your local machine, unblock the zip file in windows properties, otherwise you will get compilation errors later.  Unzip it into a blank folder to make it easy to find later.

Here is the content of the folder:

image

Add a reference to System.Data.Services.Client.dll to your windows phone project.  Now, we need to generate proxy and related classes.  To do so we will use DataSvcUtil.exe from the same folder.  Here is the command line I am using:

 

datasvcutil /uri:http://localhost:50406/PersonWcfDataService.svc/ /out:.\PersonModel.cs /DataServiceCollection /Version:2.0

As you can see I am providing my svc file’s url.  I am using version 2 of the data services.  I am outputting the proxy into PersonModel.cs file.  DataServiceCollection parameter instructs the utility to generate collections that derive from DataSericeCollection.  Next I am include this file in my project.

Next I am going to create an instance of the client in my view model as following:

PersonsDbEntities odataClient;

odataClient =

         new PersonsDbEntities(new Uri(@"http://localhost:50406/PersonWcfDataService.svc"));

 

Of course in production you need to give correct Url.  Next, I am going to query the data.  First I am going to define a property to hold my collection


        private DataServiceCollection<PersonsDbModel.Person> oDataPeople;
 
       
public DataServiceCollection<PersonsDbModel.Person
> ODataPeople
        {
           
get { return
oDataPeople; }
           
set
            {
                oDataPeople =
value
;
                NotifyPropertyChanged(
"ODataPeople");
            }
        }

 

Then I am going to query the data as following

            ODataPeople = new DataServiceCollection<PersonsDbModel.Person>(odataClient);
            ODataPeople.LoadCompleted += ODataPeople_LoadCompleted;
 
           
try
            {
                ODataPeople.LoadAsync(peopleUri);
            }
           
catch (DataServiceClientException
ex)
            {
               
MessageBox.Show(ex.ToString());
            }

 

So, first I create a collection and tie it to my client.  Without that I can query the collection.  In the callback I check for errors:

        void ODataPeople_LoadCompleted(object sender, LoadCompletedEventArgs e)
        {
           
if (e.QueryOperationResponse.Error != null
)
            {
               
MessageBox.Show(e.QueryOperationResponse.Error.ToString());
            }
        }

 

That I it.  Now I just add a listbox to my UI and bind it to this collection:

            <controls:PivotItem Header="oData">
                <!–Double line list with text wrapping–>
                <ListBox x:Name="ODataListBox" Margin="0,0,-12,0"
 
                       
ItemsSource="{Binding ODataPeople}">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Margin="0,0,0,17" Width="432">
                                <TextBlock
 
                                
Text="{Binding FirstName}"
 
                                
TextWrapping="Wrap"
 
                                
Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                                <TextBlock
 
                                
Text="{Binding LastName}"
 
                                
TextWrapping="Wrap"
 
                                
Margin="12,-6,12,0"
 
                                
Style="{StaticResource PhoneTextSubtleStyle}"/>
                            </StackPanel>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
            </controls:PivotItem
>

 

Next, adding a person via OData.  It is really simple.  I just add new person to my collection and start the save process.  DataSericeCollection  objects are smart to keep track of the changes that occur during operation on the server.


        public void InsertPersonOdata()
        {
            ODataPeople.Add(
new PersonsDbModel.Person() { FirstName = "James", LastName = "Homer", PersonID = Guid
.NewGuid() });
            odataClient.BeginSaveChanges(
SaveChangesOptions
.Batch, (ar) =>
            {
               
Deployment
.Current.Dispatcher.BeginInvoke(() =>
                {
                    odataClient = ar.AsyncState
as PersonsDbModel.PersonsDbEntities
;
                   
DataServiceResponse
response = odataClient.EndSaveChanges(ar);
                   
if
(response.IsBatchResponse)
                    {
                       
StringBuilder errors = new StringBuilder
();
                       
foreach (ChangeOperationResponse change in
response)
                        {
                           
if (change.Error != null
)
                            {
                                errors.Append(change.Error.ToString());
                            }
                        }
                       
if
(errors.Length == 0)
                        {
                           
MessageBox.Show("Success"
);
                        }
                       
else
                        {
                           
MessageBox.Show(errors.ToString());
                        }
                    }
                });
            }, odataClient);
        }

 

You can download the entire solution for both parts 1 and 2 here.  There does seem to be some flakiness in running both services from one solution, so you may have to comment WCF Service or OData service calls to test each portion.

Post to Twitter

Working with Data on Windows Phone 7 – Part 1

I am starting a short series of blog posts that will go over various techniques of working with data on Windows Phone 7.  I am going to create a Silverlight application for the phone that gets local and remote data in a number of ways.

I this first post I will build a WCF service and connect to it from phone application.  I am going to use Entity Framework Code Frist approach to expose the data through my WCF Service.

Let’s get started.

Step 1

I am going to create new phone application.  Start Visual Studio 2010 and create new project.  Select a project template for Windows Phone Pivot Application.

image

Now, I forget about pre-generated code and create a WCF service.  To do so, add new project to created solution.  To give you a head start, select template for WCF Service Application.

image

Now, it is time to get Entity Framework code first CTP 5 up and going to create database and access it.  I am going to use NuGet (install it first if you do not have it).  Right click on references in your WCF project and select add Package References.  Choose to search on line and first the CTP 5.

image

I am installing the package which will download the DLL and add references to my project.  I am also adding a reference to System.ComponentModel.DataAnnotations.

Now I am going to add my EF classes, which are POCO classes.  I am going to go for something simple, so I am creating new single object called Person along with my data context.  Person class is very simple and here is the code for it.

using System;
using System.ComponentModel.DataAnnotations;
using
System.Runtime.Serialization;
 

namespace
WcfPhoneService
{
    [
DataContract
]
   
public class Person
    {
        [
Key
]
        [
Required
]
        [
DataMember
]
       
public Guid PersonID { get; set
; }
 
        [
MaxLength
(30)]
        [
Required
]
        [
DataMember
]
       
public string FirstName { get; set
; }
 
        [
MaxLength
(30)]
        [
Required
]
        [
DataMember
]
       
public string LastName { get; set; }
    }
}

 

There are a couple of points worth noticing.  I am using data annotation attributes to denote the requirement of all my future columns in the table.  I am setting the maximum length as well as the key for the table.  I am also setting the WCF required attributes as I am going to be eventually transferring these classes to/from the phone application.  I also need to create the data context, akin to database that will contain my list of persons.  It inherits from base class in EF CTP 5 and contains the list (set) of persons.  Again. code is pretty simple:

using System.Configuration;
using System.Data.Entity;
using
System.Data.Entity.Database;
 

namespace
WcfPhoneService
{
   
public class PersonContext : DbContext
    {
       
public
PersonContext()
        {
           
//Set initializer to handle model changes
            DbDatabase.SetInitializer<PersonContext>(new PersonContextConfig
());
 
           
this
.Database.Connection.ConnectionString =
                   
ConfigurationManager.ConnectionStrings["PersonConnectionString"
]
                    .ConnectionString;
        }
 
       
/// <summary>
        /// List of persons
        /// </summary>
        public IDbSet<Person> Persons { get; set
; }
 
       
/// <summary>
        /// Add custom configurations if necessary
        /// </summary>
        /// <param name="modelBuilder">Model builder</param>
        protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder
modelBuilder)
        {
           
base.OnModelCreating(modelBuilder);
 
        }
    }
}

 

You can see an extra class in the constructor called PersonContextConfig.  This class simply controls the default database behavior of the context when the model changes.  I am setting it to recreating of the database in my case.  I also added a couple of rows of data just for the demo by overriding Seed method.

using System.Data.Entity.Database;
using
System;
 

namespace
WcfPhoneService
{
   
public class PersonContextConfig : DropCreateDatabaseIfModelChanges<PersonContext
>
    {
       
protected override void Seed(PersonContext
context)
        {
           
base
.Seed(context);
            context.Persons.Add(
new Person() { PersonID = Guid.NewGuid(), FirstName = "John", LastName = "Doe"
});
            context.Persons.Add(
new Person() { PersonID = Guid.NewGuid(), FirstName = "Jane", LastName = "Doe" });
            context.SaveChanges();
        }
    }
}

 

Now, it is time to create my service.  I am going to add just two methods to it – get list of persons and insert a new person.  When project was created, it created default IService1 interface and Service1 implementation.  I am just going to rename both to IPersonService and PersonService respectively.  Then, I am going to implement the two methods above

using System.Collections.Generic;
using
System.ServiceModel;
 

namespace
WcfPhoneService
{
    [
ServiceContract
]
   
public interface IPersonService
    {
        [
OperationContract
]
       
IEnumerable<Person
> GetPeople();
 
        [
OperationContract
]
       
void AddPerson(Person person);
    }
 
 
 
}

 

using System.Collections.Generic;
using
System.Linq;
 

namespace
WcfPhoneService
{
 
   
public class PersonService : IPersonService
    {
       
public IEnumerable<Person
> GetPeople()
        {
           
using (PersonContext context = new PersonContext
())
            {
               
return
context.Persons.OrderBy(one => one.LastName).ThenBy(one => one.FirstName).ToList();
            }
        }
 
       
public void AddPerson(Person
person)
        {
           
using (PersonContext context = new PersonContext())
            {
                context.Persons.Add(person);
                context.SaveChanges();
            }
        }
    }
}

 

Pretty simple, right.  Now I am going to switch to my Phone project.  I am going to remove all pre-generated code from all view models first and build the project to make sure it is all good.  Now, it is time to add a service reference to my WCF project.  To do so, right click on references node in phone project and choose add service reference menu item.  Click on Discover button on the service dialog box.  Change namespace to PersonService for consistency.

image

Click OK and let the studio generate all your code for you.  To see generated code, click on PersonService reference under service references, then click on Show All Files on top of Solution explorer window.  You can then drill down to see Reference.cs.  This contains all your generated code.

image

I am now going to update view model to let it connect to the service and get the list of people.  I have to create an instance of the client (proxy), setup a handler for GetPeople method, then call it.  I also add a property to hold Person collection in.  All fairly simple.  Here is the entire code:

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using
WindowsPhonePivotAppWithData.PersonService;
 
 

namespace
WindowsPhonePivotAppWithData
{
   
public class MainViewModel : INotifyPropertyChanged
    {
        PersonService.
PersonServiceClient client = new PersonService.PersonServiceClient
();
       
public
MainViewModel()
        {
 
        }
 
       
private ObservableCollection<Person
> people;
 
       
public ObservableCollection<Person
> People
        {
           
get { return
people; }
           
private set { people = value; NotifyPropertyChanged("People"
); }
        }
 
       
public void
LoadData()
        {
            client.GetPeopleCompleted += client_GetPeopleCompleted;
            client.GetPeopleAsync();
        }
 
       
void client_GetPeopleCompleted(object sender, PersonService.GetPeopleCompletedEventArgs
e)
        {
           
if (e.Error != null
)
            {
               
MessageBox
.Show(e.Error.ToString());
            }
           
else
            {
                People = e.Result;
            }
        }
 
 
       
public event PropertyChangedEventHandler
PropertyChanged;
       
private void NotifyPropertyChanged(String
propertyName)
        {
           
PropertyChangedEventHandler
handler = PropertyChanged;
           
if (null
!= handler)
            {
                handler(
this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

 

The last part is to modify the MainPage.xaml and update item template to point to the properties that belong to person class, namely last name and first name.

        <controls:Pivot Title="MY APPLICATION">
            <!–Pivot item one–>
            <controls:PivotItem Header="first">
                <!–Double line list with text wrapping–>
                <ListBox x:Name="FirstListBox" Margin="0,0,-12,0"
 
                       
ItemsSource="{Binding People}">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                          <StackPanel Margin="0,0,0,17" Width="432">
                              <TextBlock
 
                                
Text="{Binding FirstName}"
 
                                
TextWrapping="Wrap"
 
                                
Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                              <TextBlock
 
                                
Text="{Binding LastName}"
 
                                
TextWrapping="Wrap"
 
                                
Margin="12,-6,12,0"
 
                                
Style="{StaticResource PhoneTextSubtleStyle}"/>
                          </StackPanel>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
            </controls:PivotItem
>

 

Now we will just call LoadData from the code behind of MainPage.  This is just a temporary fix, ordinarily I would have the view / view model hook up elsewhere.

    public partial class MainPage : PhoneApplicationPage
    {
       
// Constructor
        public
MainPage()
        {
            InitializeComponent();
 
            DataContext =
App
.ViewModel;
           
App.ViewModel.LoadData();
        }
    }

 

That was the last part.  Now we can run the phone application in the emulator.  And we should be able to see the list of two people that were inserted in Seed() method above.

To summarize, we just consumed WCF service from the phone.  To call the same from a deployed application, we will need to change the address in ServiceReference.ClientConfig file.  That is it.

The other part I would like to try is to insert a new person.  I am going to add a button to the second pivot item and call the insert method.  I am going to just use code behind, but you can look at my past posts on how do use MVVM Light to wire up commands.

            <controls:PivotItem Header="second"> 
                <Grid>
                    <Button
 
                      
Content="Insert Person"
 
                      
Click="Button_Click"
 
                      
Width="200"
 
                      
Height="100"/>
                </Grid>
            </controls:PivotItem
>

 

Here is the code in the view model that I need to add:

        public void InsertPerson()
        {
            client.AddPersonAsync(
new Person
() 
            { PersonID =
Guid.NewGuid(), FirstName = "John", LastName = "Johnson" });
        }

 

Here is the final code for my view model:

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using
WindowsPhonePivotAppWithData.PersonService;
 
 

namespace
WindowsPhonePivotAppWithData
{
   
public class MainViewModel : INotifyPropertyChanged
    {
        PersonService.
PersonServiceClient
client;
       
public
MainViewModel()
        {
            client =
new PersonService.PersonServiceClient
();
            client.AddPersonCompleted += client_AddPersonCompleted;
            client.GetPeopleCompleted += client_GetPeopleCompleted;
        }
 
       
private ObservableCollection<Person
> people;
 
       
public ObservableCollection<Person
> People
        {
           
get { return
people; }
           
private set { people = value; NotifyPropertyChanged("People"
); }
        }
 
       
public void
LoadData()
        {
 
            client.GetPeopleAsync();
        }
 
       
void client_GetPeopleCompleted(object sender, PersonService.GetPeopleCompletedEventArgs
e)
        {
           
if (e.Error != null
)
            {
               
MessageBox
.Show(e.Error.ToString());
            }
           
else
            {
                People = e.Result;
            }
        }
 
       
public void
InsertPerson()
        {
            client.AddPersonAsync(
new Person
() 
            { PersonID =
Guid.NewGuid(), FirstName = "John", LastName = "Johnson"
});
        }
 
       
void client_AddPersonCompleted(object sender, AsyncCompletedEventArgs
e)
        {
           
if (e.Error != null
)
            {
               
MessageBox
.Show(e.Error.ToString());
            }
           
else
            {
               
MessageBox.Show("Succecss adding person"
);
                client.GetPeopleAsync();
            }
        }
 
       
public event PropertyChangedEventHandler
PropertyChanged;
       
private void NotifyPropertyChanged(String
propertyName)
        {
           
PropertyChangedEventHandler
handler = PropertyChanged;
           
if (null
!= handler)
            {
                handler(
this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

 

And that is all there is to it.  We created a WCF service and consumed it from Windows phone application.  I used Entity Framework code first to create classes and I used the same classed as data contract for my service.  In the next post of this short series I will work on consuming a custom OData service.

Post to Twitter

Entity Framework CPT 5 – Cont.

Continuing with previous post, I wanted to go over data annotations, some old and some new in CTP 5.  Of course, everything you can do with data annotations, you can do with fluent API.  Once important this to remember about data annotations is that they are used for validation as well as defining columns in database.  All data annotations are implemented as attributes.  Here are some of the attributes to remember.  Each class defines a table in the database of course.  Attributes can be used to decorate a class, by primary are used to decorate class property that become columns in a database.

  • [Key] – specified which column or columns comprise a primary key for a table.
  • [StringLength] – specifies maximum length, and optionally minimum length.  Minimum length is only used for validation, not database constraints.
  • [MaxLength] – can be used instead of StringLenth to specify maximum length for a column
  • [ConcurrencyCheck] – flags columns that participate in optimistic concurrency checks.
  • [Required] – specifies that a value is required for a property.  Column is flagged as not nullable.
  • [Timestamp] – flags time stamp columns that are typically used for concurrency checks
  • [Column] – can be used to specify a column name.  If omitted, property name becomes column name.  You can also use this attribute to control ordinal position of a column.
  • [Table] – can be used to specify a table name.  If omitted, class name becomes table name.
  • [DatabaseGenerated] can be used to signal that a data is populated via a database.  Possible values are Computed, Identity or None.  None is the default.
  • [NotMapped] added in this release.  Allows you to have a property in a class without generating a column in a database.
  • [ForeignKey] and [InverseProperty] are used for foreign key columns

 

This release also included pluggable conventions preview.  Conventions control various aspects of behavior of code first entity framework release.  For example, pluralization of table names.  You can also write your own conventions and attributes to control behavior of the entity framework.  This is extremely powerful feature that pretty much allows you to customize database generation to unlimited extent.

Post to Twitter

New Releases for ASP.NET MVS 3 and Entity Framework CTP

Since I posted my last blog on building ASP.NET MVC 3 application using Razor view engine and Entity Framework code first CTP 4, both of these technologies underwent updates.  Both are covered on Scott Guthrie’s blog.  You can read MVC 3 RC 2 announcement. and Entity Framework CTP 5 announcement.

In this post I will cover the change I had to make to compile my existing project.  Frist of all, I downloaded and installed both updates.  Here is the download link to EF CTP 5.  This link points to MVC 3 download.

Once I downloaded and installed both, I had a slew of compiler errors.  View property of the controller and VIew property of the VIew are now called ViewBag.  It is dynamic type property and you use the following syntax to access it:

this.ViewBag.Message = "Welcome to ASP.NET MVC!";

Similar syntax is used in views:

@{
    ViewBag.Title = "About Us";
}

 

This was the major change, but it was fairly mechanical. 

Entity framework changes were simple as well.  Database classes is now called DbDatabase to match other naming conventions.  Class that controls if database is recreated when model changes is now called DropCreateDatabaseIfModelChanges. Once these few changes were done I was able to run the application again.  You can download updated application here.

You can see full list of change in MVC RC 2 here.

List of changes to Entity Framework going to CTP 5 is available in ReadMe file on the download page I pointed to above.  I am going to highlight the key points below.  These are applicable to code first as a whole, not necessary to CTP 5 itself.

  • T4 templates for code first classes are included.  As a result, you can reverse engineer a model first or database first models into a set of DbSet/DbContext classes.  If you have existing database, and you want to switch to use code first approach, the process is very simple.
  • You have access to entity states (Added, Unchanged, Modified, Deleted) and property values for each property values.  Here is how you can access entity state and property values
context.Entry<BlogEntry>(entry).State = System.Data.EntityState.Unchanged;
var text = context.Entry<BlogEntry>(entry).OriginalValues["PostText"];
var newText = context.Entry<BlogEntry>(entry).CurrentValues["PostText"];

 

  • There is ability to explicitly load navigation property’s data.
context.Entry<BlogEntry>(entry).Collection<BlogCategory>().Load()

 

  • You have a property that returns ObservableCollection for a set of entries.  This is useful in WPF applications.

ObservableCollection<BlogEntry> collection = context.Entries.Local;

  • You can get data without tracking which reduces the overhead of getting the data.  You have to import System.Data.Entity namespace
var data = blogs.Skip((currentPage - 1) * pageSize).Take(pageSize).AsNoTracking().ToArray();

 

  • There is a lot of change information available from context.ChangeTracker property.
  • You can execute raw SQL Commands.  Those are accessible through context.Database.SqlCommand (akin to ExecuteNonQuery) and context.Database.SqlQuery and context.Database.SqlQuery<T> both akin to ExecuteQuery and return a collection of objects based on type you specify.  You are not responsible for materializing the results of this queries, which is pretty cool.
  • If you do not want to use EdmMetadata table which is used to detect changes to model that database cannot accommodate, you can turn this off by removing a convention from model builder.
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();

 

I am going to cover more changes in the next post.

 

Post to Twitter

Developing ASP.NET MVC 3 Application with EF CTP (Part 5)

In this post I will describe how to use MVC with a jquery grid control to display tabular data.  To start with, there is a number of grids available, some even integrate with ASP.NET MVC by providing an MVC assembly that generates the javascript for the grid.  One of these components in jqGrid.  I am not going to use MVC helper for this demo primarily because MVC component is not a free download.  As a result, I am going to just download jqGrid itself from this site.  One of the files in download is a text file that describes what script and CSS files you need to include in your project.  I am going to just include a screenshots of my project.  I am only using one theme – swanky-purse.

image

 

image

Now, we need to incorporate those scripts into my master page (_Layout.cshtml) so that I do not have to download them in each view:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<
html xmlns
="http://www.w3.org/1999/xhtml">
<
head>
    <title>@View.Title</title>
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery-1.4.1.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
    <link href="@Url.Content("~/Content/swanky-purse/jquery-ui-1.8.6.custom.css")" rel="stylesheet" type="text/css" />
    <link href="@Url.Content("~/Content/ui.jqgrid.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery.ui.core.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.ui.datepicker.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/grid.locale-en.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.jqGrid.min.js")" type="text/javascript"></script
>
</
head
>
<
body>
    <div class="page">
        <div id="header">
            <div id="title">
                <h1>
                    My MVC Application</h1>
            </div>
            <div id="logindisplay">
                @Html.Partial("_LogOnPartial"
)
           
</div>
            <div id="menucontainer">
                <ul id="menu">
                    <li>@Html.ActionLink("Home", "Index", "Home")</li>
                    <li>@Html.ActionLink("About", "About", "Home")</li>
                    <li>@Html.ActionLink("Blogs", "Index", "Blogs")</li>
                </ul>
            </div>
        </div>
        <div id="main">
            @RenderBody()
           
<div id="footer">
            </div>
        </div>
    </div
>
</
body
>
</
html>
 

 

Now, we are going to plug in query grid script into the index page that shows blog entries – Blogs\Index.cshtml.  Here is the entire cshtml file:

@{
    View.Title = "Blogs";
    Layout =
"~/Views/Shared/_Layout.cshtml"
;
}

<h2>
    Index</h2
>
<
p>
    @Html.ActionLink("Create New", "Create")
</p
>
<
table id="blogsList" class="scroll" cellpadding="0" cellspacing
="0">
</
table
>
<
div id="blogsPager" class="scroll" style="text-align
: center;">
</
div>
 
<script type="text/javascript">
    $().ready(function
() {
        $(
"#blogsList"
).jqGrid({
            url:
‘./Blogs/BlogsGridData/’
,
            datatype:
‘json’
,
            mtype:
‘GET’
,
            colNames: [
'', '', 'Title', 'Posted On'
],
            colModel: [
            { name:
'Edit', index: 'Edit', width: 80, align: 'left', sortable: false
},
            { name:
'Delete', index: 'Delete', width: 80, align: 'left', sortable: false
},
            { name:
'Title', index: 'Title', width: 300, align: 'left'
},
            { name:
'PostedOn', index: 'PostedOn', width: 100, align: 'left'
}],
            pager: $(
‘#blogsPager’
),
            rowNum: 2,
            rowList: [2, 5, 10, 20, 50],
            sortname:
‘PostedOn’
,
            sortorder:
"desc"
,
            viewrecords:
true
,
            caption:
‘Blogs’
        });
    });

</script
>

 

Let me describe the most interesting settings here.  Url is the most notable one.  It will be used to return json data for the grid.  I know I need json because my datatype is set as such.  The actual Url will be intercepted by the routing in ASP.NET MVC to my Blogs controller’s BlogGridData method.  I will show it momentarily.  I will have 4 columns (colNames) – two without headers.  Those two columns with contain edit and delete links (anchors).  The colModel property describes the layout of the columns.  Pager property simply points to a div that will be formatted as pager control for my grid.  I also specify default sort column name and direction.  The entire grid will be attached to my table with the name of blogist (see HTML portion of the cshtml file above).

Next, let me show you what my BlogGridData looks like.  I will start with the code for entire method:

        /// <summary>
        /// Get Json data for the grid
        /// </summary>
        /// <param name="sidx">Column to osrt on.  Do not change parameter name</param>
        /// <param name="sord">Sort direction.  Do not change parameter name</param>
        /// <param name="page">Current page.  Do not change parameter name</param>
        /// <param name="rows">Number of rows to get.  Do not change parameter name</param>
        /// <returns></returns>
        public ActionResult BlogsGridData(string sidx, string sord, int? page, int
? rows)
        {
           
using (BlogContext context = new BlogContext
())
            {
               
int
pageSize = rows ?? 2;
               
int
totalRecords = context.Entries.Count();
               
int totalPages = (int)Math.Ceiling((float)totalRecords / (float
)pageSize);
               
int
currentPage = page ?? 1;
               
string sortByColumnName = sidx ?? "PostedOn"
;
               
string sortDirection = sord ?? "desc"
;
 
               
var blogs = (from one in
context.Entries
                            
select
one);
               
if (sortByColumnName == "PostedOn"
)
                {
                   
if (sortDirection.Equals("desc"
))
                        blogs = blogs.OrderByDescending(blog => blog.PostedOn);
                   
else
                        blogs = blogs.OrderBy(blog => blog.PostedOn);
                }
               
else
                {
                   
if ("desc"
.Equals(sortDirection))
                        blogs = blogs.OrderByDescending(blog => blog.Title);
                   
else
                        blogs = blogs.OrderBy(blog => blog.Title);
                }
               
var
data = blogs.Skip((currentPage – 1) * pageSize).Take(pageSize).ToArray();
 
               
var jsonData = new jqGridJson
()
                {
                    total = totalPages,
                    page = currentPage,
                    records = totalRecords,
                    rows = (
                     
from blog in
data
                     
select new jqGridRowJson
                      {
                          id = blog.BlogEntryId.ToString(),
                          cell =
new string
[] { 
                               
"<a href=’" + string.Format("./Blogs/Edit/{0}", blog.BlogEntryId.ToString()) + "’>Edit</a>"
,
                               
"<a href=’" + string.Format("./Blogs/Delete/{0}", blog.BlogEntryId.ToString()) + "’>Delete</a>"
,
                                blog.Title, 
                                blog.PostedOn.Value.ToShortDateString() }
                      }).ToArray()
                };
 
               
return Json(jsonData, JsonRequestBehavior.AllowGet);
            }
        }

 

As you can see, I am creating Url’s for edit and delete links.  One important thing to remember is that parameters to any method (BlogsGridData) will be automatically parsed from query string, so you cannot change their names.  The names are hard coded in jqGrid.  In the beginning of the method I am parsing out page size, current page, etc…  Them I am selecting the data from my blogs table.  More specifically, I am creating IQueryable<BlogEntry>, which is my blogs variable.  This query actually is not executed until I access results, which is the line in bold. So, there on that line I am constructing classes that will be later serialized using json serializer.  The classes are simply helper classes because jqGrid again expects the result set in certain format.  Here are those two helper classes:

    public class jqGridJson
    {
       
public int total { get; set
; }
       
public int page { get; set
; }
       
public int records { get; set
; }
       
public jqGridRowJson[] rows { get; set; }
    }

    public class jqGridRowJson
    {
       
public string id { get; set
; }
       
public string[] cell { get; set; }
    }

 

At the end, my last line returns JsonResult class.  That is all there is to using jqGrid with MVC 3.0.  One important note is that Url’s that point to Controller methods are relative.  It took me a while to figure out why they are not invoked in IIS, but with in web server in Visual Studio.  Here is the screenshot of the final version running in IIS:

image

Please let me know if you have any questions.  You can download full solution here.

 

Thanks.

Post to Twitter

Developing ASP.NET MVC 3 Application with EF CTP (Part 4)

In this post I will examine a couple of things.  I am going to use jQuery calendar UI functionality to improve user interface.  I will also add client side validation to my input form.

First, let’s add calendar control.  To do so, we have to download jQuery UI from .http://jqueryui.com/

Once this is completed, I will copy jquery.ui.core.js and jquery.ui.datepicker.js into Scripts folder of my application and include them in my project.  I will also copy calendar.gif as image for calendar button.  Next, I will add links to those scripts to my master page – in case of Razor view engine it is _Layout.cshtml.  Here is what it looks like:

<head>
    <title>@View.Title</title>
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery-1.4.1.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
    <link href="@Url.Content("~/Content/jquery-ui-1.8.6.custom.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery.ui.core.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.ui.datepicker.js")" type="text/javascript"></script>
 
</head
>

 

It appears that if I just drag the script into _Layout.cshtml, then it does not work.  I had to add @Url.Content to make it work.  Now that this is completed, I have to update my partial page for blog entry and update my date textbox to use date picker from jQuery.  Here is what my code looks like now:

            <div class="editor-label">
                @Html.LabelFor(model => model.PostedOn)
           
</div>
            <div class="editor-field">
                @if
(Model.PostedOn.HasValue)
                {
                   
<input type="text" name="PostedOn" id="PostedOn" class="uidatepicker" 
value=@string.Format("{0:MM/dd/yyyy}", Model.PostedOn) />
                }
               
else
                { 
                   
<input type="text" name="PostedOn" id="PostedOn" class="ui-datepicker" />
                }
                @Html.ValidationMessageFor(model => model.PostedOn)
           
</div
>

 

As you can see, the code is pretty simple, but I will explain it in more detail just in case.  Since I am using formatting for the value, I would like to account for blank date.  If I do not do conditional control, my blank date will show up as “/”.  This is pretty ugly, so I am using different input controls – one with formatting, the other without.  Now, I need to call datepicker function  to setup my input control for Posted On date.  I am going to use ready function and add a small script to the bottom of my partial view I am using to edit blog:

<script type="text/javascript">
    $().ready(function
() {
        $(
‘.ui-datepicker’
).datepicker({
            dateFormat:
‘mm/dd/yy’
,
            buttonImage:
@Url.Content("~/Content/calendar.gif")
,
            buttonImageOnly:
true
,
            showOn:
"button"
        });
    });

</script
>

 

A few configuration options for date picker as pretty simple.  I am using month/day/year format, I am using the image I got from jQuery, and I showing image only, not the button and image on it.  That is all there is to it.  Now when I click on calendar image, I get calendar popup.

 

Next step is to get client validation to work.  I need a couple of scripts I am including in the code above: jquery, jquery.validate, jquery.validate.unobtrusive.  Next step is to simply enable validation on my view by calling EnableCleintValidation as in below (in bold):

@model MvcSampleApp.Models.BlogEntry
@{Html.EnableClientValidation();}
@
using
(Html.BeginForm())
{
@Html.ValidationSummary(
true
)
 
       
<fieldset
>

Here is the final version of my view:

@model MvcSampleApp.Models.BlogEntry
@{Html.EnableClientValidation();}
@
using (Html.BeginForm())
{
@Html.ValidationSummary(
true
)
 
       
<fieldset>
            <legend>Blog Post</legend>
            <div class="editor-label">
                @Html.LabelFor(model => model.Title)
           
</div>
            <div class="editor-field">
                @Html.TextBoxFor(model => model.Title) 
                @Html.ValidationMessageFor(model => model.Title)
           
</div>
            <div class="editor-label">
                @Html.LabelFor(model => model.Title)
           
</div>
            <div class="editor-field">
                @Html.DropDownListFor(model => model.CategoryID, new SelectList(Model.Categories, "CategoryId", "CategoryName", Model.CategoryID), "– Select Category –"
)
                @Html.ValidationMessageFor(model => model.CategoryID)
           
</div>
            <div class="editor-label">
                @Html.LabelFor(model => model.PostText)
           
</div>
            <div class="editor-field">
                @Html.TextAreaFor(model => model.PostText) 
                @Html.ValidationMessageFor(model => model.PostText)
           
</div>
            <div class="editor-label">
                @Html.LabelFor(model => model.PostedOn)
           
</div>
            <div class="editor-field">
                @if
(Model.PostedOn.HasValue)
                {
                   
<input type="text" name="PostedOn" id="PostedOn" class="ui-datepicker" value=@string.Format("{0:MM/dd/yyyy}", Model.PostedOn) />
                }
               
else
                { 
                   
<input type="text" name="PostedOn" id="PostedOn" class="ui-datepicker" />
                }
                @Html.ValidationMessageFor(model => model.PostedOn)
           
</div>
            <div>
                <input type="submit" value=@TempData["Action"] />
            </div>
            @Html.Hidden("BlogEntryId"
)
       
</fieldset>
 
}
 

<script type="text/javascript">
    $().ready(function
() {
        $(
‘.ui-datepicker’
).datepicker({
            dateFormat:
‘mm/dd/yy’
,
            buttonImage:
@Url.Content("~/Content/calendar.gif")
,
            buttonImageOnly:
true
,
            showOn:
"button"
        });
    });

</script
>

 

You can see that validation works by typing one letter into title and tabbing out. You will see immediate error without post back.  This is because I have a rule on my title:

        [Display(Name = "Title")]
        [
StringLength
(30, MinimumLength = 5)]
        [
Required
]
       
public string Title { get; set; }

 

image

And that is all there is to it.

Thanks.

Post to Twitter

Developing ASP.NET MVC 3 Application with EF CTP (Part 3)

Today I will concentrate on refactoring existing code and adding other links to my application, such as delete and edit links.

First things first, let’s do a bit of refactoring in advance of adding more views.  As I noticed, edit, delete and create views are the same with the exception of title for the submit button,  So, I am going to create a partial view that encompasses basic edit functionality along with submit button.  I am going to extract the title into a variable using TempData dictionary off the ViewResult object.  For example, here is how I am going to put “Delete” label into the view result:

view.TempData.Add("Action", "Delete");

 

I will use the same Action key in create and add methods as well.  Here is what code in my controller look like for the entire delete method:

        public ActionResult Delete(int id)
        {
           
BlogEntry entry = null
;
           
using (BlogContext context = new BlogContext
())
            {
                entry = context.Entries.Find(id);
                entry.CategoryID = entry.Category.CategoryId;
                entry.Categories = GetCaregories();
            }
           
var
view = View(entry);
            view.TempData.Add(
"Action", "Delete"
);
           
return view;
        }

 

Now I am going to refactor the view itself.  I am creating new view following the same routing as in part 2 of the post, but I will check Partial View checkbox.  Here is what my partial view (CreatePartial.cshtml) looks like:

@model MvcSampleApp.Models.BlogEntry
 
  @using (Html.BeginForm()) {
        @Html.ValidationSummary(true)
 
        <fieldset>
            <legend>Blog Post</legend>
            
            <div class="editor-label">
                @Html.LabelFor(model => model.Title)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(model => model.Title)
                @Html.ValidationMessageFor(model => model.Title)
            </div>
 
                          <div class="editor-label">
                @Html.LabelFor(model => model.Title)
            </div>
            <div class="editor-field">
                @Html.DropDownListFor(model=>model.CategoryID, 
new SelectList(Model.Categories, "CategoryId", "CategoryName", Model.CategoryID), 
"– Select Category –")
                @Html.ValidationMessageFor(model => model.CategoryID)
            </div>
            
            <div class="editor-label">
                @Html.LabelFor(model => model.PostText)
            </div>
            <div class="editor-field">
                @Html.TextAreaFor(model => model.PostText)
                @Html.ValidationMessageFor(model => model.PostText)
            </div>
            
            <div class="editor-label">
                @Html.LabelFor(model => model.PostedOn)
            </div>
            <div class="editor-field">
                @Html.TextBox("PostedOn", string.Format("{0:MM/dd/yyyy}", Model.PostedOn))
                @Html.ValidationMessageFor(model => model.PostedOn)
            </div>
            <div>
                  <input type="submit" value=@TempData["Action"] />
             </div>
             @Html.Hidden("BlogEntryId")
        </fieldset>
 
    }

 

Now, our old Create view looks as follows:

@model MvcSampleApp.Models.BlogEntry
 
@{
    View.Title = "Create";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
 
<h2>Create</h2>
@{Html.RenderPartial("CreatePartial", Model);}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>
 
 

 

Super simple.  Delete and Edit views look identical with exception of the title.  Very clean end result for all my refactoring efforts.  Here is the final code for my controller:

using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web.Mvc;
using
MvcSampleApp.Models;
 

namespace
MvcSampleApp.Controllers
{
   
public class BlogsController : Controller
    {
       
//
        // GET: /Blogs/
 
       
public ActionResult
Index()
        {
           
using (BlogContext context = new BlogContext
())
            {
                context.Database.Connection.ConnectionString =
                   
ConfigurationManager.ConnectionStrings["BlogsConnectionString"
].ConnectionString;
               
var blogs = (from one in
context.Entries
                            
orderby one.PostedOn descending
                             select
one).ToList();
               
return
View(blogs);
            }
        }
 
       
//
        // GET: /Blogs/Create
 
 
       
public ActionResult
Create()
        {
           
IEnumerable<BlogCategory
> categories = GetCaregories();
           
var view = View(new BlogEntry
() { Categories = categories });
            view.TempData.Add(
"Action", "Create"
);
           
return
view;
        }
 
       
private static IEnumerable<BlogCategory
> GetCaregories()
        {
           
IEnumerable<BlogCategory
> categories;
           
using (BlogContext context = new BlogContext
())
            {
                categories = (
from one in
context.Categories
                             
orderby
one.CategoryName
                             
select
one).ToList();
            }
           
return
categories;
        }
 
       
private BlogCategory GetCategory(int
categoryID)
        {
           
using (BlogContext context = new BlogContext
())
            {
               
return
context.Categories.Find(categoryID);
            }
        }
 
       
//
        // POST: /Blogs/Create
 
        [
HttpPost
]
       
public ActionResult Create(BlogEntry
entry)
        {
 
           
try
            {
               
if
(entry.CategoryID > 0)
                {
                    entry.Category = GetCategory(entry.CategoryID);
                }
               
if
(TryValidateModel(entry))
                {
                   
using (BlogContext context = new BlogContext
())
                    {
                        context.Entries.Add(entry);
                        context.SetAsUnchanged(entry.Category);
                        context.SaveChanges();
                    }
 
                   
return RedirectToAction("Index"
);
                }
               
else
                {
                    entry.Categories = GetCaregories();
                   
return
View(entry);
                }
            }
           
catch
            {
               
return
View();
 
            }
        }
 
       
//
        // GET: /Blogs/Edit/5
 
       
public ActionResult Edit(int
id)
        {
           
BlogEntry entry = null
;
           
using (BlogContext context = new BlogContext
())
            {
                entry = context.Entries.Find(id);
                entry.CategoryID = entry.Category.CategoryId;
                entry.Categories = GetCaregories();
            }
           
var
view = View(entry);
            view.TempData.Add(
"Action", "Update"
);
           
return
view;
        }
 
       
//
        // POST: /Blogs/Edit/5
 
        [
HttpPost
]
       
public ActionResult Edit(int id, BlogEntry
entry)
        {
           
try
            {
               
if
(entry.CategoryID > 0)
                {
                    entry.Category = GetCategory(entry.CategoryID);
                }
               
if
(TryValidateModel(entry))
                {
                    entry.BlogEntryId = id;
                   
using (BlogContext context = new BlogContext
())
                    {
                        context.Entries.Attach(entry);
                        context.SetAsModified(entry);
                        context.SaveChanges();
                    }
 
                   
return RedirectToAction("Index"
);
                }
               
else
                {
                    entry.Categories = GetCaregories();
                   
return
View(entry);
                }
            }
           
catch
            {
               
return
View();
 
            }
        }
 
       
//
        // GET: /Blogs/Delete/5
 
       
public ActionResult Delete(int
id)
        {
           
BlogEntry entry = null
;
           
using (BlogContext context = new BlogContext
())
            {
                entry = context.Entries.Find(id);
                entry.CategoryID = entry.Category.CategoryId;
                entry.Categories = GetCaregories();
            }
           
var
view = View(entry);
            view.TempData.Add(
"Action", "Delete"
);
           
return
view;
        }
 
       
//
        // POST: /Blogs/Delete/5
 
        [
HttpPost
]
       
public ActionResult Delete(int id, BlogEntry
entry)
        {
          
try
            {
               
if
(entry.CategoryID > 0)
                {
                    entry.Category = GetCategory(entry.CategoryID);
                }
               
if
(TryValidateModel(entry))
                {
                    entry.BlogEntryId = id;
                   
using (BlogContext context = new BlogContext
())
                    {
                        context.Entries.Attach(entry);
                        context.Entries.Remove(entry);
                        context.SaveChanges();
                    }
 
                   
return RedirectToAction("Index"
);
                }
               
else
                {
                    entry.Categories = GetCaregories();
                   
return
View(entry);
                }
            }
           
catch
            {
               
return View();
 
            }
        }
    }
}

 

A couple more things to notice.  By default foreign keys are created with Cascade Deletes option.  This is not appropriate behavior for my use case.  I am changing this behavior in OnModelCreating method of my context.  Here is the final version of my context class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using System.Configuration;
using
System.Data.Entity.ModelConfiguration;
 

namespace
MvcSampleApp.Models
{
   
public class BlogContext : DbContext
    {
       
public
BlogContext()
        {
           
this
.Database.Connection.ConnectionString =
                   
ConfigurationManager.ConnectionStrings["BlogsConnectionString"
]
                    .ConnectionString;
        }
       
public DbSet<BlogCategory> Categories { get; set
; }
       
public DbSet<BlogEntry> Entries { get; set
; }
 
       
protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder
modelBuilder)
        {
           
base
.OnModelCreating(modelBuilder);
 
            modelBuilder.Entity<
BlogEntry
>().HasKey(a => a.BlogEntryId);
            modelBuilder.Entity<
BlogCategory
>().HasKey(a => a.CategoryId);
            modelBuilder.Entity<
BlogEntry>().HasRequired(e => e.Category).WithMany().WillCascadeOnDelete(false
);
        }
 
       
public void SetAsModified(object
entry)
        {
           
this.ObjectContext.ObjectStateManager.ChangeObjectState(entry, System.Data.EntityState
.Modified);
        }
 
       
public void SetAsUnchanged(object
entry)
        {
           
this.ObjectContext.ObjectStateManager.ChangeObjectState(entry, System.Data.EntityState.Unchanged);
        }
    }
}

 

I am using helper methods to SetAs… to ensure that I am not creating duplicate categories.  You can see how I am using these helper methods above in controller class.

You can download entire solution here.

Post to Twitter

Developing ASP.NET MVC 3 Application with EF CTP (Part 2)

First thing we want to do is create a controller for blog entries.  To do so, we will right-click on Controllers folder, select Add, then Controller.

image

On next screen we give it a name (BlogsController) and check the checkbox to create CRUD operations:

image

First method we are going to fill is Index method that will return the list of blog entries.  We will not use EF to return the list of blog posts sorted in ascending order by date.  We are not going to implement paging for now, we will come back to do this later.  Here is completed Index method(Index is just a naming convention)

        public ActionResult Index()
        {
           
using (BlogContext context = new BlogContext
())
            {
                context.Database.Connection.ConnectionString = 
                   
ConfigurationManager.ConnectionStrings["BlogsConnectionString"
].ConnectionString;
               
var blogs = (from one in
context.Entries
                            
orderby one.PostedOn descending
                             select
one).ToList();
               
return View(blogs);
            }
        }

 

As you can see the code is pretty simple.  Next step is to create index view. To do this right-click in the body of the method above and select Add View

image

Below you can see the options I selected.  We create strongly typed view based on BlogEntry class.  We use Razor (new in MVC 3.) engine and select list as view type.  Once we click Add, the IDE will scaffold the object and build the HTML view for us – Index.cshtml.  This new view will be added to Blogs folder.  Again we are using naming conventions to match controller and view

 

image

We are going to clean up the view by removing ID and text columns from the table.  We also update links to use appropriate ID from the object.  Here is final version of our view:

 

@model IEnumerable<MvcSampleApp.Models.BlogEntry>
 
@{
    View.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
 
    <h2>Index</h2>
 
    <p>
        @Html.ActionLink("Create New", "Create")
    </p>
 
    <table>
        <tr>
            <th></th>
            <th>
                Title
            </th>
            <th>
                PostedOn
            </th>
        </tr>
 
    @foreach (var item in Model) {
    
        <tr>
            <td>
                @Html.ActionLink("Edit", "Edit", new { id=item.BlogEntryId }) |
                @Html.ActionLink("Details", "Details", new { id=item.BlogEntryId }) |
                @Html.ActionLink("Delete", "Delete", new { id=item.BlogEntryId })
            </td>
            <td>
                @item.Title
            </td>
            <td>
                @String.Format("{0:g}", item.PostedOn)
            </td>
        </tr>
    
    }
 
    </table>
 
 

 

To make this work, I had to update by Blog Entry class.  I had to add category ID in order to bind to it in the UI.  Question now is: looks like I need model objects on top of EF classes.  This seems counter-productive to me as I would have to duplicate properties.  I think the goal would be to use composition or inheritance to have model derive or expose EF class.  I will work on refactoring efforts right after the app is working.

    public class BlogEntry
    {
        [
Key
]
       
public int BlogEntryId { get; private set
; }
 
        [
Display(Name = "Title"
)]
        [
StringLength
(30, MinimumLength = 5)]
        [
Required
]
       
public string Title { get; set
; }
 
        [
Display(Name = "Post Text"
)]
        [
StringLength(int
.MaxValue)]
        [
Required
]
       
public string PostText { get; set
; }
 
        [
Display(Name = "Category"
)]
       
public virtual BlogCategory Category { get; set
; }
 
        [
Display(Name = "Post Date"
)]
        [
Range(typeof(DateTime), "1/1/1900", "12/31/2099"
)]
        [
Required
]
       
public DateTime? PostedOn { get; set
; }
 
       
public IEnumerable<BlogCategory> Categories { get; set
; }
 
        [
Required
]
        [
Display(Name = "Category"
)]
       
public int CategoryID { get; set; }
    }

 

In Razor syntax @ symbol indicates C# code, where < symbol indicates HTML tags.  As you can see on top we define model for the view, which in our case is the argument passed into the View in the Index method of the controller.  We also need to add a link to the menu for blog posts.  We add it to the _Layout.cshtml view:


                <ul id="menu">
                    <li>@Html.ActionLink("Home", "Index", "Home")</li>
                    <li>@Html.ActionLink("About", "About", "Home")</li>
                    <li>@Html.ActionLink("Blogs", "Index", "Blogs")</li>
                </ul>

 

Next step is to create new post view.  We also need to add code to Create method of the new view.  Here is how Create method looks:

        public ActionResult Create()
        {
           
return View(new BlogEntry());
        }

 

Now, same step as above – right-click, add view, select Create option from View Content drop down.  Then I will remove ID field.  Here is the end result of that.

@model MvcSampleApp.Models.BlogEntry
 
@{
    View.Title = "Create";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
 
<h2>Create</h2>
 
    @using (Html.BeginForm()) {
        @Html.ValidationSummary(true)
 
        <fieldset>
            <legend>Blog Post</legend>
            
            <div class="editor-label">
                @Html.LabelFor(model => model.Title)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(model => model.Title)
                @Html.ValidationMessageFor(model => model.Title)
            </div>
 
                          <div class="editor-label">
                @Html.LabelFor(model => model.Title)
            </div>
            <div class="editor-field">
                @Html.DropDownListFor(model=>model.CategoryID, new SelectList(Model.Categories, "CategoryId", "CategoryName", Model.CategoryID), "– Select Category –")
                @Html.ValidationMessageFor(model => model.Title)
            </div>
            
            <div class="editor-label">
                @Html.LabelFor(model => model.PostText)
            </div>
            <div class="editor-field">
                @Html.TextAreaFor(model => model.PostText)
                @Html.ValidationMessageFor(model => model.PostText)
            </div>
            
            <div class="editor-label">
                @Html.LabelFor(model => model.PostedOn)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(model => model.PostedOn)
                @Html.ValidationMessageFor(model => model.PostedOn)
            </div>
            <div>
                                   <input type="submit" value="Create" />
                          </div>
        </fieldset>
 
    }
 
    <div>
        @Html.ActionLink("Back to List", "Index")
    </div>
 
 

Next step is to create controller method to save new blog post

        [HttpPost]
       
public ActionResult Create(BlogEntry
entry)
        {
 
           
try
            {
               
if
(entry.CategoryID > 0)
                {
                    entry.Category = GetCategory(entry.CategoryID);
                }
               
if
(TryValidateModel(entry))
                {
                   
using (BlogContext context = new BlogContext
())
                    {
                        context.Database.Connection.ConnectionString =
                   
ConfigurationManager.ConnectionStrings["BlogsConnectionString"
]
                    .ConnectionString;
                        context.Entries.Add(entry);
                        context.SaveChanges();
                    }
 
                   
return RedirectToAction("Index"
);
                }
               
else
                {
                    entry.Categories = GetCaregories();
                   
return
View(entry);
                }
            }
           
catch
            {
               
return View();
 
            }
        }

 

There are still parts of the method that can be optimized.  I will look at those once the application is completed.

In the next post I will look at the edit and delete methods.

Post to Twitter

Developing ASP.NET MVC 3 Application with EF CTP (Part 1)

I this post I will walk through steps of creating an ASP.NET MVC 3 application using new code first entity framework CTP as data access and business layer.  Just a few upfront comments.  Both technologies are in preview state right now, but will likely be released in first half of next year.

To get started we have to download and install them.  To make this simpler, I will use NuGet (formerly  NuPack) which is package management software for .NET applications.  You can find it here.  Visual Studio 2010 is required to follow along with the demo, by the way.  You can download ASP.NET MVC 3.0 beta here.

Now that it has been downloaded and installed, let’s create new project.

image

Next step to pick the view engine you want to use.  You can select either ASPX (ASP.NET) or new Razor engine that will ship with MVC 3.0 and new product – Web Matrix.

image

We will go ahead and also select to create Unit Test project.

What the wizard builds for us is empty site with home view and registration service that uses membership provider.  Let’s run the app to see if everything worked correctly.  We can open web.config and verify that the system is using ASP.NET SQL Membership provider for login:

<configuration>
  <
connectionStrings
>
    <
add name=ApplicationServices

         connectionString=data source=.\SQLEXPRESS;Integrated Security=SSPI;
AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true

         providerName=System.Data.SqlClient
/>
  </
connectionStrings>
 
  <appSettings
>
    <
add key=enableSimpleMembership value=false
/>
    <
add key=ClientValidationEnabled value=false
/>
    <
add key=UnobtrusiveJavaScriptEnabled value=true
/>
  </
appSettings>
 
  <system.web
>
 
    <authentication mode=Forms
>
      <
forms loginUrl=~/Account/LogOn timeout=2880
/>
    </
authentication>
 
    <membership
>
      <
providers
>
        <
clear
/>
        <
add name=AspNetSqlMembershipProvider
 
            
type=System.Web.Security.SqlMembershipProvider
 
            
connectionStringName=ApplicationServices
             enablePasswordRetrieval=false
 
            
enablePasswordReset=true
 
            
requiresQuestionAndAnswer=false
 
            
requiresUniqueEmail=false
             maxInvalidPasswordAttempts=5
 
            
minRequiredPasswordLength=6
             minRequiredNonalphanumericCharacters=0
 
            
passwordAttemptWindow=10
             applicationName=/
/>
      </
providers
>
    </
membership
>

Now, let’s add our code.  Since I absolutely lack any imagination, I will create blogging application.  Each blog will contain title, text, posted date and category.  Let’s create entities for blogs and categories using EF code first CTP.  First, let’s install CTP 4 for entity framework.  To do, we will use NuGet functionality.  Right click on references node in solution and select add package, search for EF and Select EFCTP 4:

image

 

image

Now, let’s create our two classes – categories and blog posts.  We will add them to the Model folder. Blog category class is very simple:

    public class BlogCategory
    {
        [
Key
]
       
public int CategoryId { get; private set
; }
 
        [
Display(Name = "Category Name"
)]
       
public string CategoryName { get; internal set; }
 
    }

 

I made blog entries property virtual to enable lazy loading.  Blog entry class is only slightly mode complicated:

    public class BlogEntry
    {
        [
Key
]
       
public int BlogEntryId { get; private set
; }
 
        [
Display(Name = "Title"
)]
        [
StringLength
(30, MinimumLength = 5)]
        [
Required
]
       
public string Title { get; set
; }
 
        [
Display(Name = "Post Text"
)]
        [
StringLength
(30, MinimumLength = 5)]
        [
Required
]
       
public string PostText { get; set
; }
 
        [
Display(Name = "Category"
)]
       
public BlogCategory Category { get; set
; }
 
        [
Display(Name = "Post Date"
)]
        [
Range(typeof(DateTime), "1/1/1900", "12/31/2099"
)]
       
public DateTime? PostedOn { get; set; }
    }

 

As you can see, I am using attributes from DataAnnotations namespace to describe the properties of my classes.  Next class I need is DbContext, which essentially is my database abstraction:

    public class BlogContext : DbContext
    {
       
public DbSet<BlogCategory> Categories { get; set
; }
       
public DbSet<BlogEntry> Entries { get; set
; }
 
       
protected override void OnModelCreating(

          System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
        {
           
base
.OnModelCreating(modelBuilder);
 
            modelBuilder.Entity<
BlogEntry
>().HasKey(a => a.BlogEntryId);
            modelBuilder.Entity<
BlogCategory>().HasKey(a => a.CategoryId);
 
        }
    }

 

 

As you can see I have two properties – for blog entries and categories.  I also modify default configuration of my database by overriding OnModelCreating and specifying my primary key columns and table names.  One more class I would like to add to customize database creation behavior that is very useful for development:

    public class BlogDatabase :

       System.Data.Entity.Infrastructure.RecreateDatabaseIfModelChanges<BlogContext>
    {
       
protected override void Seed(BlogContext
context)
        {
            context.Categories.Add(
new BlogCategory()

             { CategoryName = “General” });
            context.Categories.Add(
new BlogCategory()

             { CategoryName = “Entity Framework” });
            context.Categories.Add(
new BlogCategory()

             { CategoryName = “Silverlight” });
        }
    }

 

This class inherits for recreate database behavior.  I am overriding Seed method to prepopulate my database with a handful of categories.  Now, I have to register my class in global.asax.  I am doing so by setting initializer in static method on database class.

        protected void Application_Start()
        {
           
AreaRegistration
.RegisterAllAreas();
           
Database.SetInitializer<BlogContext>(new BlogDatabase
());
 
            RegisterGlobalFilters(
GlobalFilters
.Filters);
            RegisterRoutes(
RouteTable.Routes);
        }

In the next post I will add some web pages to use these classes. 

Post to Twitter

Using Entity Framework 4.0 CTP

In this post I will take a look at the new features in the next release of entity framework.

Primary feature set is centered around what is commonly referred to as “Code First” approach to Entity Framework.  With code first approach you write the code first, then entity framework runtime dynamically figures out how to persist your classes to database.

So, you start with plain ol’ LCR classes (POCO classes).  For my small example I will have list of companies with their contacts.  Here is what my classes look like:

        public Company()
        {
            Contacts = new ObservableCollection<CompanyContact>();
            Contacts.CollectionChanged += (o, e) =>
                {
                    if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
                    {
                        foreach (var item in e.NewItems)
                        {
                            (item as CompanyContact).ParentCompany = this;
                        }
                    }
                };
        }
        public int CompanyId { get; set; }
        public string CompanyName { get; set; }
        public DateTime DateAdded { get; set; }
        public virtual ObservableCollection<CompanyContact> Contacts { get; private set; }
    }
 
    public class CompanyContact
    {
        public int CompanyContactId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public Company ParentCompany { get; set; }
    }

 

Now we need to take a look at key classes that enable POCO persistence in Entity Framework CTP : DbSet and DbContext.

DbSet is a set of POCO classes that is pretty much a simplified version of ObjectSet.  It gives developers ability to add and remove items to.  DbContext is really at heart of CTP version, and it is a simplified version of ObjectContext.  It may contain any number of properties that are of type DbSet<T> where T is any POCO class.

Here is what this class looks like for my Rolodex mini-application:

    public class CompanyContext : DbContext
    {
        public CompanyContext()
            : base()
        {
        }
        public DbSet<Company> Companies { get; set; }
 
        public DbSet<CompanyContact> Contacts { get; set; }

 

That is all we need to do at a high level, dealing with out POCO classes.  Now, the key part – let’s define our rules and persistence details.  There is a number of ways this can be done, I am picking virtual method OnModelCreating on DbContext that allows me to configure rules and persistence details.  Here is what I am doing for my couple of classes:

        protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
 
            // configure primary key
            modelBuilder.Entity<Company>()
                .HasKey(c => c.CompanyId);
 
            // company id is identity
            modelBuilder.Entity<Company>().Property(c => c.CompanyId)
                .StoreGeneratedPattern = System.Data.Metadata.Edm.StoreGeneratedPattern.Identity;
 
            //maximum length for company name
            modelBuilder.Entity<Company>()
               .Property(c => c.CompanyName).MaxLength = 40;
 
            //name required
            modelBuilder.Entity<Company>()
                .Property(c => c.CompanyName).Optional = false;
 
            // One to many relationship
            modelBuilder.Entity<Company>()
                .HasMany(c => c.Contacts);
 
            //contact id is identity
            modelBuilder.Entity<CompanyContact>().Property(c => c.CompanyContactId)
                .StoreGeneratedPattern = System.Data.Metadata.Edm.StoreGeneratedPattern.Identity;
 
            // primary key for contacts
            // company cannot be null
            modelBuilder.Entity<CompanyContact>()
                .HasKey(c => c.CompanyContactId)
                .HasRequired(c => c.ParentCompany);
 
            //last name required
            modelBuilder.Entity<CompanyContact>()
                .Property(c => c.LastName).Optional = false;
 
            //maximum length for last name
            modelBuilder.Entity<CompanyContact>()
                .Property(c => c.LastName).MaxLength = 50;
 
            //first name required
            modelBuilder.Entity<CompanyContact>()
               .Property(c => c.FirstName).Optional = false;
 
            //maximum length for first name
            modelBuilder.Entity<CompanyContact>()
              .Property(c => c.FirstName).MaxLength = 30;
 
 
        }

 

As you can see from my comments I am configuring nullable / non nullable properties via Optional properties off Property method.  I am also configuring Identity properties via StoreGeneratedPattern.  I am also configuring maximum length for my fields at the same time.

The next step is to create a database and add data.  Creating database is super easy with DbContext:

            using (var context = new CompanyContext())
            {
                context.Database.Connection.ConnectionString = @"Server=(local);Database=RolodexEFCtp;Trusted_Connection=True;";
                context.Database.CreateIfNotExists();

 

That is all that takes.  At the time my context is created, OnModelCreating will fire, thus configuring all my persistence options.  Now, let’s populate DB with data:

                var company = new Company()
                    {
                        CompanyName = "Mine",
                        DateAdded = DateTime.Now
                    };
                context.Companies.Add(company);
 
                company.Contacts.Add(new CompanyContact()
                {
                    FirstName = "Sergey",
                    LastName = "Basrskiy"
                });
 
                company.Contacts.Add(new CompanyContact()
                {
                    FirstName = "John",
                    LastName = "Doe"
                });
 
                company = new Company()
                {
                    CompanyName = "Yours",
                    DateAdded = DateTime.Now
                };
                context.Companies.Add(company);
 
                company.Contacts.Add(new CompanyContact()
                {
                    FirstName = "Jane",
                    LastName = "Doe"
                });
 
                company.Contacts.Add(new CompanyContact()
                {
                    FirstName = "John",
                    LastName = "James"
                });
                context.SaveChanges();

 

As before, the last line of dealing with saving is calling SaveChanges() method. 

Now, let’s take a look at how to get the data back from database:

            using (var context = new CompanyContext())
            {
                context.Database.Connection.ConnectionString = @"Server=(local);Database=RolodexEFCtp;Trusted_Connection=True;";
                var companies = context.Set<Company>().Include("Contacts").OrderBy(c => c.CompanyName).ToList();
            }

 

The last line will get me the list of companies, each populated with the list of corresponding contacts.  At this point I am doing everything that Entity Framework is designed for – get me the data from database and save data to database, except now I am configuring everything in code and creating storage on the fly.  Most importantly, I use POCO classes instead of Entity classes.

Now we just have to wait and see when new version of Entity Framework is released.

You can download CTP here: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=4e094902-aeff-4ee2-a12d-5881d4b0dd3e&displaylang=en

You can find more details on CTP on entity framework team blog: http://blogs.msdn.com/b/adonet/archive/2010/07/14/ctp4codefirstwalkthrough.aspx

Thanks

Post to Twitter

ReMix Talk

As I posted previously, I talked at Atlanta ReMix 2010 conference past Saturday.  Entire event was a a success, we had over 200 people there.  We had great presenters and good topics.  My topic was “Microsoft Silverlight and Windows Azure: A Match Made for the Web”

You can download PowerPoint presentation here.  You can download solution here.  To get solution up and going, you need to have Visual Studio 2010 installed, along with Silverlight 4 tools and Azure tools.  You will also need to sign up for an account on Azure and SQL Azure.  You will need to update web.config file and ServiceReference.ClientConfig file.

Please let me know if you have any questions.

Thank you.

Post to Twitter

Entity Framework 4.0 and Multiple Data Contexts

In the EF version 1.0, there was a problem when one would try to update multiple contexts as part of a single transaction.  For example, I can use Transaction Scope, the update one context, then second context.  Here is sample code to illustrate:

 

using (TransactionScope scope = new TransactionScope())
{
    try
    {
        using (RolodexEntities context = new RolodexEntities())
        {
            context.Connection.Open();

            Company company = new Company();
            company.CompanyName = "Test 1";
            company.DateAdded = DateTime.Today;
            context.AddToCompanies(company);
            context.SaveChanges();

            using (RolodexEntities context2 = new RolodexEntities(context.Connection as EntityConnection))
            {
                Company company2 = new Company();
                company2.CompanyName = "Test 1";
                company2.DateAdded = DateTime.Today;
                context2.AddToCompanies(company2);
                context2.SaveChanges();
            }
        }

        scope.Complete();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

This code in version 1.0 would throw an exception when second context’s constructor was called.  The exception was quite obscure and was referring to the fact that the connection was already open.  This was actually correct, but that was the whole reason I was passing in the connection.  I was trying to make sure that my transaction would not get promoted to Distributed Transactions Coordinator.  The transaction would always get promoted as soon as there are multiple SQL Server connections used within using scope/.end using scope code block.  So, in version 1.0 MSDTC would be required in the code above.

This issue still exists in EF 4.0.  You can vote to fix the issue here : https://connect.microsoft.com/data/feedback/details/533240/cannot-share-a-store-connection-between-multiple-contexts-in-order-to-avoid-dtc-promotion

Here is the code that confirms the problem:

using (TransactionScope scope = new TransactionScope())
{
    try
    {
        using (RolodexEntities context = new RolodexEntities())
        {
            context.Connection.Open();

            Company company = new Company();
            company.CompanyName = "Test 11";
            company.DateAdded = DateTime.Today;
            context.AddToCompanies(company);
            context.SaveChanges();

            RolodexEntities1 contextTemp = new RolodexEntities1();
            MetadataWorkspace space = (contextTemp.Connection as EntityConnection).GetMetadataWorkspace();
            EntityConnection connection = new EntityConnection(space, (context.Connection as EntityConnection).StoreConnection);

            using (RolodexEntities1 context2 = new RolodexEntities1(connection))
            {
                User user = new User();
                user.UserName = "test";
                user.Role = "User";
                context2.AddToUsers(user);
                context2.SaveChanges();
            }
        }

        scope.Complete();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

Please feel free to ask any questions on this subject.

Post to Twitter

RIA Services (Cont.)

I am going to continue exploring the topic of RIA services and Silverlight.  I thought I was going to get into updates in this post, but there are a few topics I would like to cover first.  I am going to try to get to updates in the next post.

Today, I am going to explore two more topics.  I am going to cover extending RIA Services DomainContext with custom classes and working on including child objects when fetching a parent object using Entity Framework and RIA Services.

 

First, I am going to extend my DomainContext with a custom class.  In my case I have Company Object/Table with a number of columns.  In my Silverlight application I would like to have a list of companies that shows only company name.  When a user selected one company, I would like to fetch full company object with company contacts child object.  If I were to use the method that the wizard built for me – public IQueryable<Companies> GetCompanies(),I would get the full object with all columns.  So, I am going to build a custom class that only has company ID and name:

    public class ReadOnlyCompany

    {

        [Key]

        public int CompanyId { internal set; get; }

        public string CompanyName { internal set; get; }

    }

 

I am going to add this class to RIA Service project on .NET side (SilverlightRIAServicesLibrary.Web project in my case).  As you notice I did not have to decorate my class with DataContract attribute or decorate properties with DataMember attribute.  We do not actually need to do this, as RIA Services will take care of all that for us.  I do however need to use Key attribute or I would get a compile time error.  Each object is required to have a key (primary key) property.  Next step is to write a method in DomainService (RoldexDomainService in my case) class.  Here is what this would look like:

        public List<ReadOnlyCompany> GetReadOnlyCompanies()

        {

            return (from oneCompany in this.ObjectContext.Companies

                    orderby oneCompany.CompanyName

                    select new ReadOnlyCompany()

                    {

                        CompanyId = oneCompany.CompanyId,

                        CompanyName = oneCompany.CompanyName

                    }).ToList<ReadOnlyCompany>();

        }

 

Even though I return List object here, but RIA Services will actually return ReadOnlyObservableCollection<ReadOnlyCompany> on Silverlight side.  You have to remember that when you cast return value for RIA Services call to a specific object.  Here is what this call would look like on Silverlight side:

        private void GetCompaniesList()

        {

            ShowPleaseWaitMessage();

            var query = _context.GetReadOnlyCompaniesQuery();

 

            _context.Load<ReadOnlyCompany>(query, LoadBehavior.RefreshCurrent, (o) =>

            {

                HidePleaseWaitMessage();

                if (o.Error != null)

                    ErrorHandler.HandleException(o.Error);

                else

                {

                    this.Model = o.Entities as ReadOnlyObservableCollection<ReadOnlyCompany>;

                }

                    HidePleaseWaitMessage();

            }, null); ;

 

        }

Here I am putting up a please wait window, fire a query and interpret the results.  As I mention before, my next step is to get full Company object based on selected ID.  Again, I am adding a new method to DomainService class on .NET side:

        public Companies GetCompany(int companyID)

        {

            var returnValue = this.ObjectContext.Companies

                .Include("CompanyContacts")

                .Include("CompanyContacts.CompanyContactPhones")

                .Where(one => one.CompanyId == companyID).FirstOrDefault();

            return returnValue;

        }

Now, let’s see what this call looks like on Silverlight side.  This also demonstrates the use of parameters:

var companyQuery = _context.GetCompanyQuery(_companyID);

_context.Load<Companies>(companyQuery, (o1) =>

{

    HidePleaseWaitMessage();

    if (o.Error != null)

    {

        ErrorHandler.HandleException(o.Error);

    }

    else

    {

        this.Model = o1.Entities.First() as Companies;

    }

}, null);

As you can see, RIA services build us a query that already has the same company ID parameter for us.  Pretty cool!  However, if I look at return value (Companies object), I will notice that contacts property is actually null even though I did add .Include statement to my custom Entity Framework based method.  To get this to work, I have to modify the metadata class that RIA Services generated(RolodexDomainService.metadata.cs in my case).  I need to open this class file and look for Companies object.  I will find public EntityCollection<CompanyContactPhones> CompanyContactPhones property in it.  To get RIA Services to include child collection, I need to add Include attribute here as well:

[Include]

public EntityCollection<CompanyContactPhones> CompanyContactPhones;

I would have to take the same step to include phones collection for each contact.  If I run my code again, I will not get Company object with a list of Contacts, each containing a list of Phones.

I will try to cover update in my next post.

Thank you and do not hesitate to ask questions.

Post to Twitter

Entity Framework and multiple relationships between two tables

Here is a scenario – I have two tables – Users and Phones.  Users table has two columns that relate to Phones table – PrimaryPhone and SecondaryPhone.  If you build an EF model with these two tables, you will end up with Users entity with two navigation properties that relate to Phones entity – Phones and Phones1.  Yes, I hope this excellent :-( naming convention will be fixed in EF 2.0.  Our goal – retrieve the data for both phones with each user.  If you do the following:

var query = (from oneUser in Users.Include(“Phones”)

you will end up with only secondary (or primary) navigation property in Users object populated.  So, either Users.Phones or Users.Phones1 will have data, the other one will be null.  Important thing to realize when working with Entity Framework is that “.Includes”  statement works off navigation property names, not table names.  So, if you would like to populate both primary and secondary phone, you need to use the following query:

var query = (from oneUser in Users.Include(“Phones”).Include(“Phones1”)

Post to Twitter

Using Entity Framework as Data Access Layer in n-Tier applications

I have been using Entity framework as DAL for a CSLA for Silverlight based application.  I have player a role in uncovering a number of issues that make it very hard to use in these circumstances.  Here is my (surely incomplete) list.

1. Foreign keys handling.  The actual IDs that are used as foreign keys are not built as properties when you generate a model from a database.  Instead you get navigation properties.  For example, you have User and UserTypes table.  Users table has UserTypeID in it.  When you build a mode for this, you will have UserTypes property in Users entity, but not access to UserTypeID.  As a result, when you are rehydrating a users object in n-Tier environment, you have to have an instance of UserTypes entity to attach a user to.  Your options are to retrieve it from database (inefficient) or write a helper class that creates one on the fly.  To do so, you create an instance of UserTypes entity, then set entity key on it, then attach it to context.  To do all this, you will need to know ID in advance.  You can do this by using UserTypesReference property in Users entity – it will contain UserTypesID when you retrieve an instance of Users from DB.  You can store it in a property of the user object (CSLA for example) that you will use in UI.

2.  Another foreign key annoyance is an instance when you have multiple columns from one table relating to another table.  For example, Users table has columns PrimaryType and SecondaryType, both relating to UseTypes table.  As a result you will get navigation properties UserTypes1 and UserTypes2 in Users entity.  This is pretty much useless because as you write code against that, you will need to constantly have your model open to figure out what ID you need to use.  On top of that, if you use .Include(“UserTypes”) syntax to get the user with both primary and secondary columns, only one of the UserTypes properties will be populated with an instance of UserTypes if you have different IDs in property and secondary columns.  What do you do then?  Your only option is to use UserTypes1(2)Reference property to either get an ID or retrieve an instance of UserTypes table

3.  Third foreign key issue is concurrency handling.  Typically, for all properties you can indicate if a column is to participate in concurrency handling.  For some reason, you cannot do the same for navigation properties – they always participate in concurrency handling if they are changing.  As a result, you have to always keep track of old and new value for each navigation property,  You would set its old value before attaching it to the context, then set it to the new value.  If you capture the SQL query that is sent to the DB when the values are not the same, you will find navigation properties are part of the where clause / concurrency checking.  Sad but true.

4.  Re-using context for Oracle and SQL server (or any multiple databases).  Currently Microsoft ships entity framework only with SQL Server provider.  So, you are stuck buying some third party Oracle provider and hope that the model it generates will be the same as SQL server model, so that you only need to change connection string when switching databases.  There is a promise we might get there one day, but today is not that day.

Post to Twitter