Skip to content

Instantly share code, notes, and snippets.

@emoa2l
Created June 21, 2013 14:36
Show Gist options
  • Save emoa2l/5831606 to your computer and use it in GitHub Desktop.
Save emoa2l/5831606 to your computer and use it in GitHub Desktop.
AutofacServiceStackAdapter
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);
}
}
}
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; }
}
}
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