Monday, November 17, 2014

WCF – Service contract in a different project


I strongly recommend to implement service contracts in a separated project, why? Because in some scenarios I will need to share my contracts with external client applications, just because adding a "Web reference" is not a good idea, I agree it is easy, fast and can be updated from Visual Studio, but generated code is not managed by the developer & modify it is just a bug itself.
When adding a WCF Service application to your solution, your new project will looks like this:



The Visual Studio template has done all the job for you:
  • IService1 contains the service contract
  • Service1.svc.cs is the service it self
Ok, thanks Visual Studio for your help, but I prefer to do it by myself. First of all, "Service1" is not a proper name for a service, just remove the items generated by the Visual Studio and add a new WCF Service to your project (BusinessService in this example):



Once again, Visual Studio try to help me adding service contract and the service implementation in the project. This is not what I want so, I'm going to remove the IBusinessService, as I want it to be declared in a different project.
Add a new project "ToAllMicrosoftDevsOutThere.Service.Contracts" to your solution, the implementation of your service contract will be there, including DataContracts and MessageContracts. Following references must be added to your contracts project:
  • System.ServiceModel
  • System.Runtime.Serialization (for DataContracts/DataMember)
My service will contain just one operation (by now), defined on the service interface IBusinessService, which looks like:


[ServiceContract]
public interface IBusinessService
{
   [OperationContract]
   DoWorkResponse DoWork(DoWorkRequest request);
}

 

There are two interesting things on this interfaces:
  • My service interface must have the attribute 'ServiceContract'
  • All my service operations must have the attribute 'OperationContract'
Next step, my Service can receive complex objects as requests and send complex responses. These objects usually named DTO (Data Transfer Objects), should not contain any business logic, only properties (get/set) containing all the data my service needs in order to provide a response. For defining these DTO I will use MessageContracts:


[MessageContract]
public class DoWorkRequest
{
   [MessageBodyMember]
   public BusinessObjectDto BusinessEntity
   { get; set; }
}


[MessageContract]
public class DoWorkResponse
{
   [MessageBodyMember]
   public bool ItWasOk
   { getset}
}

 
In the previous code, I'm already using a DataContract (a data contract is a complex data type in my message contract):


[DataContract]
public class BusinessObjectDto
{
   [DataMember]
   public string Name
   { getset}
}

 
I need to add a reference to my contracts project on my service project and, now my projects structure looks like:



After adding the reference to my contracts project I can implement my Service contract on my service like follow:


namespace ToAllMicrosoftDevsOutThere.Service.Host
{
   public class BusinessService : IBusinessService
   {
      public DoWorkResponse DoWork(DoWorkRequest request)
      {
         return new DoWorkResponse() { ItWasOk true };
      }
   }
}

 
And that's all, just taking some minutes doing the setup of my WCF Service, I will be able to provide my Contract in a single DLL to any external application (.NET client…)
Enjoy coding!

Sunday, November 16, 2014

Basic solution structure in Visual Studio



This is just a quick note about the way I structure my solutions in Visual Studio, it is not a good practice or a standard, it is just the way I like to structure my solutions. 


Create the solution

I know you can create your first project and creating the solution at the same time, but, come on! You are going to create your solution only once, take the time (and the pleasure) for creating it properly.



Use solution folders

This is the best way for structure all you projects within the solution. I structure my projects in folders depending of the module they belong.



Order your folders

As you can see on the previous picture I have created a folder for each layer in my applications (Client & Service), personally I like order my projects from more external to deeper layer (understanding my database layer is the deeper one).



 

Enjoy coding

Now I have created my solution structure I can follow up writing other posts using this solution structure!

Sunday, November 2, 2014

NHibernate - Configuración




Partamos de un dominio sencillo: Autores literarios y sus libros, nuestro dominio sería algo como:


public class Author
{
   public virtual int Id
   { getset; }
   public virtual string FirstName
   { get; set; }

   public virtual string LastName

   { get; set; }

   public virtual IEnumerable<Book> Books

   { getset; }
}

 

public class Book
{
   public virtual int Id
   { getset; }
   public virtual string Title
   { get; set; }

   public virtual string Description
   { get; set; }

   public virtual Author Author

   { getset; }
}

Para asegurar la independencia de nuestro dominio de la tecnología que utilicemos para el acceso a datos, en este caso NHibernate, vamos a crear un nuevo proyecto y añadir la referencia a NHibernate en este nuevo proyecto. Además de la referencia a NHibernate, he añadido la una referencia a FluentNHibernate, para poder configurar mi dominio (prometo volver sobre el uso de Fluent en otro post).
En este momento nuestro proyecto tiene la estructura siguiente:







El siguiente pase es la configuración del mapping de NHibernate, para ello vamos a utilizar Fluent NHibernate. Cada objeto del dominio se mapea en una clase ClassMap de nuestro proyecto de acceso a datos:

 

public class AuthorMap : ClassMap<Author>

{
   public AuthorMap()
   {
      Id(x => x.Id)
               .Column("Id")
               .GeneratedBy.Identity();
      Map(x => x.FirstName).Column("FirstName").Not.Nullable();

      Map(x => x.LastName).Column("LastName").Nullable();
      HasMany(x => x.Books)
                    .KeyColumn("AuthorId")
                    .Inverse()
                    .Cascade.AllDeleteOrphan();
   }
}

 

public class BookMap : ClassMap<Book>

{
   public BookMap()
   {
      Id(x => x.Id)
               .Column("Id")
               .GeneratedBy.Identity();
      Map(x => x.Title).Column("Title").Not.Nullable();

      Map(x => x.Description).Column("Description").Nullable();
      References(x => x.Author).Column("AuthorId");
   }
}

Ya solo queda crear un proyecto de tests para probar nuestra configuracion, el test siguiente prueba el almacenamiento de un autor y su libro asociado


[TestClass]

public class DataTests

{

   private static ISessionFactory _sessionFactory;


    [TestInitialize]
   public void Init()
   {
      _sessionFactory Fluently.Configure()
                                .Database(MsSqlConfiguration.MsSql2012
                                .ConnectionString(x => x.FromConnectionStringWithKey("sample")))
                                .Mappings(m => m.FluentMappings.AddFromAssemblyOf<AuthorMap>())
                                .BuildSessionFactory();
   }

    [TestMethod]
   public void SaveAuthor_Author_AuthorSaved()
   {
      var author new Author()
      {
         FirstName "Orson",
         LastName "Scott Card",
         Books new List<Book>() {
            new Book()
            {
               Description "Ender's Game is a 1985 military science fiction novel",
               Title"Ender's Game"

            }
         }
      };

      using (var session = _sessionFactory.OpenSession())

      using (var transaction = session.BeginTransaction())
      {
         session.SaveOrUpdate(author);
      }
   }
}