Created
June 21, 2013 14:36
-
-
Save emoa2l/5831606 to your computer and use it in GitHub Desktop.
AutofacServiceStackAdapter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Ctc.Business.Objects.Common; | |
using Ctc.Business.Raven; | |
using Ctc.Services.Stella2Api.Messages; | |
using Ctc.Services.Stella2Api.Services; | |
using Ctc.Services.Stella2Api.Services.Requests; | |
using Ctc.Services.Stella2Api.Services.RequestValidators; | |
using Ctc.Services.Stella2Api.Services.Responses; | |
using CTC.Toolbox; | |
using NHibernate; | |
using NServiceBus; | |
using Raven.Client; | |
using ServiceStack.Common; | |
using ServiceStack.FluentValidation; | |
using ServiceStack.Redis; | |
using ServiceStack.Redis.Messaging; | |
using ServiceStack.ServiceHost; | |
using ServiceStack.ServiceInterface.Validation; | |
using ServiceStack.WebHost.Endpoints; | |
using System; | |
using System.Collections.Generic; | |
using System.Collections.Specialized; | |
using System.Configuration; | |
using System.Data; | |
using System.Linq; | |
using System.Net; | |
using System.Web; | |
[assembly: WebActivator.PreApplicationStartMethod(typeof(Ctc.Services.Stella2Api.App_Start.AppHost), "Start")] | |
namespace Ctc.Services.Stella2Api.App_Start | |
{ | |
public class AppHost | |
: AppHostBase | |
{ | |
public AppHost() //Tell ServiceStack the name and where to find your web services | |
: base("Stella2 Application API", typeof(AccessService).Assembly) | |
{ | |
//LogManager.LogFactory = new Log4NetFactory(true); | |
} | |
public override void Configure(Funq.Container container) | |
{ | |
container.Adapter = new AutofacServiceStackAdapter(AutofacContainer.RootScope.Value); | |
//Set JSON web services to return idiomatic JSON camelCase properties | |
ServiceStack.Text.JsConfig.EmitCamelCaseNames = true; | |
RavenDocument.Initialize(); | |
container.Register(x => RavenDocument.Instance); | |
GetAppsettings(container); | |
SetupNh(container); | |
//container.Register<NHibernate.ISessionFactory>(new NhSession().GetSessionFactory()); | |
//Uncomment to change the default ServiceStack configuration | |
SetConfig(new EndpointHostConfig()); | |
//Enable Authentication | |
Stella2Auth(container); | |
var redisFactory = new PooledRedisClientManager("10.0.0.31:6379"); | |
container.Register<IRedisClientsManager>(redisFactory); | |
var mqHost = new RedisMqServer(redisFactory); | |
MessageQueueing.SetupMessageQueueing(mqHost); | |
container.Register(mqHost); | |
var mqClient = container.Resolve<RedisMqServer>().CreateMessageQueueClient(); | |
mqClient.Publish(new ClientNotification{MessageId = 1L}); | |
var bus = NServiceBus.Configure.With() | |
.Log4Net() | |
.DefineEndpointName("uberendpoint") | |
.DefaultBuilder() | |
.XmlSerializer() | |
.MsmqTransport().IsTransactional(false).PurgeOnStartup(false) | |
.UnicastBus().ImpersonateSender(false).SendOnly(); | |
//.CreateBus() | |
//.Start(); | |
container.Register(bus); | |
//Register all your dependencies | |
//container.Register(new TodoRepository()); | |
Plugins.Add(new ValidationFeature()); | |
container.RegisterValidators(typeof(CatalogLookupValidator).Assembly); | |
} | |
/// <summary> | |
/// Registers our custom service runner that instantiates an Nhibernate session per request and | |
/// handles flushing the session or rolling back the session before sending the response. | |
/// </summary> | |
/// <typeparam name="TRequest">The type of the request.</typeparam> | |
/// <param name="actionContext">The action context.</param> | |
/// <returns></returns> | |
public override IServiceRunner<TRequest> CreateServiceRunner<TRequest>(ActionContext actionContext) | |
{ | |
return new BaseServiceRunner<TRequest>(this, actionContext); | |
} | |
private static void GetAppsettings(Funq.Container container) | |
{ | |
var appSettings = ConfigurationManager.AppSettings; | |
container.Register(appSettings); | |
} | |
private static void SetupNh(Funq.Container container) | |
{ | |
var nhsessions = new Dictionary<string, ISessionFactory>(); | |
using (var ravenSession = container.Resolve<IDocumentStore>().OpenSession()) | |
{ | |
var customers = ravenSession.Query<Customer>(); | |
foreach (var customer in customers) | |
{ | |
var constring = | |
string.Format("Data Source={1};Initial Catalog={0};Integrated Security=SSPI", | |
customer.DatabaseName, container.Resolve<NameValueCollection>()["dbserver"]); | |
nhsessions.Add(customer.SID, new NhSession().GetSessionFactory(constring)); | |
} | |
} | |
container.Register(new SessionFactoryStore(nhsessions)); | |
} | |
/// <summary> | |
/// sets up our request and response filters | |
/// the request filter handles validation of the apikey and apitoken | |
/// the response filter sets an http status is necessary and attaches any exceptions to the resposne. | |
/// </summary> | |
/// <param name="container">The container.</param> | |
private void Stella2Auth(Funq.Container container) | |
{ | |
RequestFilters.Add((req, res, dto) => | |
{ | |
var thisDto = dto as CtcRequest; | |
if (thisDto == null) return; | |
if (!req.IsLocal && !req.IsSecureConnection) | |
{ | |
var permitHttp = bool.Parse(container.Resolve<NameValueCollection>()["permitHttp"]); | |
if(!permitHttp) | |
throw new Exception("Only https permitted"); | |
} | |
var raw = req.AbsoluteUri; | |
var url = new Uri(raw); | |
var queryParams = HttpUtility.ParseQueryString(url.Query); | |
var token = req.Headers["x-api-token"]; | |
var key = req.Headers["x-api-key"]; | |
var uid = 0; | |
try | |
{ | |
uid = int.Parse(req.Headers["x-user-id"]); | |
} | |
catch (Exception ex) | |
{ | |
Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception(string.Format("sid: {0}", thisDto.Sid), ex)); | |
} | |
if (string.IsNullOrEmpty(token)) | |
{ | |
token = queryParams["x-api-token"]; | |
} | |
if (string.IsNullOrEmpty(key)) | |
{ | |
key = queryParams["x-api-key"]; | |
} | |
if (string.IsNullOrEmpty(token)) | |
{ | |
token = req.FormData["x-api-token"]; | |
} | |
if (string.IsNullOrEmpty(key)) | |
{ | |
key = req.FormData["x-api-key"]; | |
} | |
if (uid == 0) | |
{ | |
uid = int.Parse(req.FormData["x-user-id"]); | |
} | |
//Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception(string.Format("token: {0}", token))); | |
//Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception(string.Format("key: {0}", key))); | |
//Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception(string.Format("uid: {0}", uid))); | |
if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(key)) | |
{ | |
res.StatusCode = (int) HttpStatusCode.Unauthorized; | |
throw new UnauthorizedAccessException(); | |
} | |
using (var session = container.Resolve<IDocumentStore>().OpenSession()) | |
{ | |
var cust = | |
session.Query<Customer>() | |
.Where(a => a.SubscribedApps.Any(app => app.AppId == "Stella2")) | |
.SingleOrDefault(x => x.AuthKey == key && x.AuthToken == token); | |
if (cust == null) | |
{ | |
res.StatusCode = (int) HttpStatusCode.Unauthorized; | |
throw new UnauthorizedAccessException(); | |
} | |
var user = | |
session.Query<User>() | |
.SingleOrDefault(x => x.CustomerSID == cust.SID && x.Id == uid); | |
if (user == null) | |
{ | |
res.StatusCode = (int)HttpStatusCode.Unauthorized; | |
throw new UnauthorizedAccessException(); | |
} | |
var subbedapp = cust.SubscribedApps.SingleOrDefault(x => x.AppId == "Stella2"); | |
if (subbedapp != null) | |
thisDto.AccessLevel = | |
subbedapp.AccessLevel; | |
thisDto.RequestTime = DateTime.UtcNow; | |
thisDto.Uid = user.Id; | |
thisDto.Sid = cust.SID; | |
} | |
}); | |
ResponseFilters.Add((req, res, dto) => | |
{ | |
var thisDto = dto as CtcResponse; | |
if (thisDto == null) return; | |
if (req.Items.ContainsKey("error")) | |
{ | |
var exception = req.Items["error"] as Exception; | |
if (exception != null) | |
{ | |
TypeSwitch.Do( | |
exception, | |
TypeSwitch.Case<UnauthorizedAccessException>( | |
() => res.StatusCode = (int) HttpStatusCode.Unauthorized) | |
); | |
thisDto.Error = exception; | |
} | |
} | |
thisDto.ResponseTime = DateTime.UtcNow; | |
}); | |
} | |
public static void Start() | |
{ | |
new AppHost().Init(); | |
} | |
} | |
/// <summary> | |
/// Store Nhibernate session factories in a dictionary keyed on customer.sid | |
/// </summary> | |
class SessionFactoryStore | |
{ | |
public SessionFactoryStore(Dictionary<string, ISessionFactory> factories) | |
{ | |
_factories = factories; | |
} | |
private readonly Dictionary<string, ISessionFactory> _factories; | |
public ISession Open(string sid) | |
{ | |
return _factories[sid].OpenSession(); | |
} | |
} | |
/// <summary> | |
/// our custom service runner | |
/// </summary> | |
/// <typeparam name="TRequest"></typeparam> | |
public class BaseServiceRunner<TRequest> : ServiceRunner<TRequest> | |
{ | |
public BaseServiceRunner(AppHost appHost, ActionContext actionContext) | |
: base(appHost, actionContext) { } | |
public override void OnBeforeExecute(IRequestContext requestContext, TRequest request) | |
{ | |
var req = request as CtcRequest; | |
if (req == null) | |
base.OnBeforeExecute(requestContext, request); | |
else | |
{ | |
var validator = TryResolve<AbstractValidator<TRequest>>(); | |
if (validator != null) validator.ValidateAndThrow(request); | |
var store = TryResolve<SessionFactoryStore>(); | |
var session = store.Open(req.Sid); | |
var trans = session.BeginTransaction(IsolationLevel.ReadCommitted); | |
requestContext.SetItem("session", session); | |
requestContext.SetItem("transaction", trans); | |
requestContext.SetItem("ctcrequest", req); | |
} | |
} | |
public override object OnAfterExecute(IRequestContext requestContext, object response) | |
{ | |
var trans = requestContext.GetItem("transaction") as ITransaction; | |
if (trans != null && trans.IsActive) | |
trans.Commit(); | |
var session = requestContext.GetItem("session") as ISession; | |
if (session != null) | |
{ | |
session.Flush(); | |
session.Close(); | |
} | |
return base.OnAfterExecute(requestContext, response); | |
} | |
public override object HandleException(IRequestContext requestContext, TRequest request, Exception ex) | |
{ | |
var req = request as CtcRequest; | |
if(req != null) | |
{ | |
var trans = requestContext.GetItem("transaction") as ITransaction; | |
if (trans != null && trans.IsActive) | |
trans.Rollback(); | |
var session = requestContext.GetItem("session") as ISession; | |
if (session != null) | |
{ | |
session.Flush(); | |
session.Close(); | |
} | |
Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception(string.Format("customer: {0}", req.Sid), ex)); | |
} | |
requestContext.SetItem("exception", ex); | |
return base.HandleException(requestContext, request, ex); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Web; | |
using Autofac; | |
using Autofac.Integration.Mvc; | |
namespace Ctc.Services.Stella2Api | |
{ | |
public static class AutofacContainer | |
{ | |
static AutofacContainer() | |
{ | |
RootScope = new Lazy<ILifetimeScope>(BuildContainer, true); | |
} | |
static IContainer BuildContainer() | |
{ | |
var builder = new ContainerBuilder(); | |
//builder.RegisterAssemblyModules(typeof(NHModule).Assembly); | |
//builder.RegisterFilterProvider(); | |
//builder.RegisterControllers(typeof(NHModule).Assembly); | |
//Builder.RegisterType<DefaultFormsAuthentication>().As<IFormsAuthentication>(); | |
var container = builder.Build(); | |
//CommandProcessor.RootScope = Container; | |
return container; | |
} | |
public static Lazy<ILifetimeScope> RootScope { get; private set; } | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Ctc.Services.Stella2Api | |
{ | |
public class AutofacServiceStackAdapter : IContainerAdapter, IRelease | |
{ | |
private readonly ILifetimeScope _container; | |
public static ILifetimeScopeProvider ScopeProvider; | |
public AutofacServiceStackAdapter(ILifetimeScope container) | |
{ | |
_container = container; | |
} | |
private ILifetimeScope GetScope() | |
{ | |
return ScopeProvider != null ? ScopeProvider.GetLifetimeScope() : _container; | |
} | |
public T Resolve<T>() | |
{ | |
return GetScope().Resolve<T>(); | |
} | |
public T TryResolve<T>() | |
{ | |
T result; | |
return GetScope().TryResolve(out result) ? result : default(T); | |
} | |
public void Release(object instance) | |
{ | |
//do nothing | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment