Skip to content

Instantly share code, notes, and snippets.

@JoshClose
Created November 15, 2011 05:10
Show Gist options
  • Save JoshClose/1366219 to your computer and use it in GitHub Desktop.
Save JoshClose/1366219 to your computer and use it in GitHub Desktop.
Setting Up WCF with Multiple Services and Multiple Databases Using NHibernate and Ninject 2
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using Wnn.Business.Repositories;
using Wnn.Service.Contract.DataContracts;
using Wnn.Service.Contract.ServiceContracts;
namespace Wnn.Service
{
[ServiceBehavior( InstanceContextMode = InstanceContextMode.PerCall )]
public class BlogService : IBlogService
{
private readonly UserRepository userRepository;
private readonly PostRepository postRepository;
private readonly TagRepository tagRepository;
public BlogService( UserRepository userRepository, PostRepository postRepository, TagRepository tagRepository )
{
this.userRepository = userRepository;
this.postRepository = postRepository;
this.tagRepository = tagRepository;
}
public Post GetPostById( int id )
{
return ConvertPost( postRepository.Get( id ) );
}
public User GetUserById( int id )
{
return ConvertUser( userRepository.Get( id ) );
}
public User GetUserByUserNameAndPassword( string userName, string password )
{
return ConvertUser( userRepository.GetByUserNameAndPassword( userName, password ) );
}
public List<Post> GetPosts()
{
return ( from p in postRepository.GetAll()
select ConvertPost( p ) ).ToList();
}
public List<Post> GetPostsFromAuthor( string userName )
{
return ( from p in postRepository.GetAllForUser( userName )
select ConvertPost( p ) ).ToList();
}
private static User ConvertUser( Business.Objects.User userData )
{
User user = null;
if( userData != null )
{
user = new User
{
Email = userData.Email,
FirstName = userData.FirstName,
Id = userData.Id,
LastName = userData.LastName,
UserName = userData.UserName,
};
}
return user;
}
private static Post ConvertPost( Business.Objects.Post postData )
{
Post post = null;
if( postData != null )
{
post = new Post
{
Author = postData.Author.UserName,
Content = postData.Content,
Created = postData.Created,
Id = postData.Id,
Title = postData.Title,
Tags = ( from t in postData.Tags
select t.Name ).ToList()
};
}
return post;
}
}
}
using System;
using System.Runtime.Remoting.Messaging;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using NHibernate;
using Ninject;
using Wnn.Business;
namespace Wnn.Service.Host
{
public class NHibernateInstanceProvider : IInstanceProvider
{
private const string sessionKey = "ThreadSession";
private const string transactionKey = "ThreadTransaction";
private readonly Type serviceType;
private static SessionManager SessionManager
{
get { return CallContext.GetData( sessionKey ) as SessionManager; }
set { CallContext.SetData( sessionKey, value ); }
}
private static ITransaction Transaction
{
get { return CallContext.GetData( transactionKey ) as ITransaction; }
set { CallContext.SetData( transactionKey, value ); }
}
public NHibernateInstanceProvider( Type serviceType )
{
this.serviceType = serviceType;
}
public object GetInstance( InstanceContext instanceContext )
{
return GetInstance( instanceContext, null );
}
public object GetInstance( InstanceContext instanceContext, Message message )
{
var connectionStringKey = GetConnectionStringKey( serviceType );
var kernel = new StandardKernel( new NinjectSetup( connectionStringKey ) );
SessionManager = kernel.Get<SessionManager>();
Transaction = SessionManager.BeginTransaction();
var instance = kernel.Get( serviceType );
return instance;
}
public void ReleaseInstance( InstanceContext instanceContext, object instance )
{
try
{
Transaction.Commit();
}
catch
{
Transaction.Rollback();
}
finally
{
SessionManager.Close();
SessionManager.Dispose();
}
}
private static string GetConnectionStringKey( Type serviceType )
{
// All of our database connections should
// go here. We could also put all of these types
// into a config file and load them dynamically.
string connectionStringKey;
if( serviceType == typeof( BlogService ) )
{
connectionStringKey = "Dashboard";
}
else
{
throw new Exception( "Service type '{0}' does not match any database connection." );
}
return connectionStringKey;
}
}
}
using NHibernate;
using Ninject.Modules;
using Wnn.Business;
namespace Wnn.Service.Host
{
public class NinjectSetup : NinjectModule
{
private readonly string connectionStringKey;
public NinjectSetup( string connectionStringKey )
{
this.connectionStringKey = connectionStringKey;
}
public override void Load()
{
Bind<ISession>()
.ToMethod( ctx => SessionFactoryFactory.GetSessionFactory( connectionStringKey ).OpenSession() )
.InSingletonScope();
Bind<SessionManager>()
.ToSelf()
.InSingletonScope();
}
}
}
using System.Collections.Generic;
using System.Linq;
using Wnn.Business.Objects;
namespace Wnn.Business.Repositories
{
public class PostRepository : RepositoryBase<Post>
{
public PostRepository( SessionManager sessionManager ) : base( sessionManager ){}
public List<Post> GetAllForUser( string userName )
{
return ( from p in SessionManager.Linq<Post>()
where p.Author.UserName == userName
select p ).ToList();
}
}
}
using System.Collections.Generic;
using System.Linq;
namespace Wnn.Business.Repositories
{
public abstract class RepositoryBase<T>
{
protected SessionManager SessionManager { get; set; }
protected RepositoryBase( SessionManager sessionManager )
{
SessionManager = sessionManager;
}
public T Get( int id )
{
return SessionManager.Get<T>( id );
}
public List<T> GetAll()
{
return SessionManager.Linq<T>().ToList();
}
public void SaveOrUpdate( T obj )
{
SessionManager.SaveOrUpdate( obj );
}
public void Delete( T obj )
{
SessionManager.Delete( obj );
}
}
}
using System.Collections.Generic;
using System.ServiceModel;
namespace Wnn.Service.Host
{
public class ServiceHostEngine
{
private readonly List<ServiceHost> serviceHosts = new List<ServiceHost>();
public ServiceHostEngine()
{
// We can have multiple services listed here.
// We could actually have a list of services in a config
// file that is dynamically loaded here also.
serviceHosts.Add( new ServiceHost( typeof( BlogService ) ) );
}
public void Start()
{
foreach( var serviceHost in serviceHosts )
{
serviceHost.Open();
}
}
public void Stop()
{
foreach( var serviceHost in serviceHosts )
{
serviceHost.Close();
}
}
}
}
using System.Collections.Generic;
using FluentNHibernate.Cfg;
using NHibernate;
namespace Wnn.Business
{
public static class SessionFactoryFactory
{
private static readonly object locker = new object();
private static readonly Dictionary<string, ISessionFactory> sessionFactories = new Dictionary<string, ISessionFactory>();
public static ISessionFactory GetSessionFactory( string connectionStringKey )
{
ISessionFactory sessionFactory;
sessionFactories.TryGetValue( connectionStringKey, out sessionFactory );
// Double check locking is used here because
// WCF could have many instances accessing this
// code at the same time.
if( sessionFactory == null )
{
lock( locker )
{
sessionFactories.TryGetValue( connectionStringKey, out sessionFactory );
if( sessionFactory == null )
{
sessionFactory = Fluently.Configure()
.Database(
FluentNHibernate.Cfg.Db.MsSqlConfiguration.MsSql2005.ConnectionString(
c => c.FromConnectionStringWithKey( connectionStringKey ) )
.ProxyFactoryFactory( "NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu" ) )
.Mappings( m => m.FluentMappings.AddFromAssembly( typeof( SessionFactoryFactory ).Assembly ) )
.ExposeConfiguration( cfg => cfg.SetProperty( "generate_statistics", "true" ) )
.ExposeConfiguration( cfg => cfg.SetProperty( "adonet.batch_size", "10" ) )
.BuildSessionFactory();
sessionFactories[connectionStringKey] = sessionFactory;
}
}
}
return sessionFactory;
}
}
}
using Wnn.Business.Objects;
namespace Wnn.Business.Repositories
{
public class TagRepository : RepositoryBase<Tag>
{
public TagRepository( SessionManager sessionManager ) : base( sessionManager ){}
}
}
using System.Linq;
using Wnn.Business.Objects;
namespace Wnn.Business.Repositories
{
public class UserRepository : RepositoryBase<User>
{
public UserRepository( SessionManager sessionManager ) : base( sessionManager ){}
public User GetByUserNameAndPassword( string userName, string password )
{
return ( from u in SessionManager.Linq<User>()
where u.UserName == userName && password == u.Password
select u ).SingleOrDefault();
}
}
}
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="nhibernateServiceBehavior" type="Wnn.Service.Host.NHibernateBehaviorExtensionElement, Wnn.Service.Host, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>
<behaviors>
<serviceBehaviors>
<behavior name="nhibernateServiceBehavior">
<nhibernateServiceBehavior />
<serviceMetadata />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="HttpEnableBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="Wnn.Service.BlogService" behaviorConfiguration="nhibernateServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8761/Services/" />
</baseAddresses>
</host>
<endpoint address="Blog" binding="netTcpBinding" contract="Wnn.Service.Contract.ServiceContracts.IBlogService" />
</service>
</services>
</system.serviceModel>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment