ITenantIdentificationStrategy用于Azure WorkerRole中的Autofac

时间:2014-10-08 21:41:29

标签: c# azure autofac

我有一个Azure WorkerRole,可以处理多租户应用程序的服务总线消息。我正在使用Autofac Multitenant扩展,但很难确定如何根据传入的服务总线消息正确识别租户。

我的当前代码会导致内存快速溢出,因为每次收到消息时都会重新加载内核,这不起作用。

using System;
using System.Reflection;
using System.Threading;
using Autofac;
using Autofac.Extras.Multitenant;    
using Microsoft.ServiceBus;
using Microsoft.ServiceBus.Messaging;
using Microsoft.WindowsAzure.ServiceRuntime;

namespace CAR.ServiceBusWorkerRole
{
    public class WorkerRole : RoleEntryPoint
    {
        public static IContainer Kernel;
        private const string TopicName = "DataUpdateTopic";
        private const string SubscriptionName = "DataUpdateSub";
        private static Tracing Tracing = new Tracing("ServiceBus");
        SubscriptionClient _client;
        private bool IsStopped;

        public override void Run()
        {

            while (!IsStopped)
            {
                try
                {
                    // Receive the message
                    var receivedMessage = _client.Receive();
                    if (receivedMessage == null)
                    {
                        Thread.Sleep(1000);
                        continue;
                    }

                    if (receivedMessage != null)
                    {
                        if (receivedMessage.DeliveryCount > 1)
                        {
                            Tracing.Error(String.Format("Deadlettering message: message {0}", receivedMessage));
                            receivedMessage.DeadLetter();
                            continue;
                        }

                        try
                        {
                            //Get actual message type
                            var messageBodyType =
                                Type.GetType(receivedMessage.Properties["messageType"].ToString());
                            if (messageBodyType == null)
                            {
                                //Should never get here as a messagebodytype should
                                //always be set BEFORE putting the message on the queue
                                Tracing.Error(String.Format("Message does not have a messagebodytype" +
                                                            " specified, message {0}", receivedMessage.MessageId),
                                    TracingLogPartion.Error);
                                receivedMessage.DeadLetter();
                                continue;
                            }

                            Tracing.Information(String.Format("Received Message Of Body: {0}", messageBodyType));
                            //get tenant name
                            var tenant = receivedMessage.Properties["tenant"];
                            if (tenant == null)
                            {
                                Tracing.Error(String.Format("Message does not have a tenant" +
                                                            " specified, message {0}", receivedMessage.MessageId),
                                    TracingLogPartion.Error);
                                receivedMessage.DeadLetter();
                                continue;
                            }

                            Kernel = BuildKernel(tenant.ToString());

                            //Use reflection to figure out the type
                            //of object contained in the message body, and extract it
                            MethodInfo method = typeof (BrokeredMessage).GetMethod("GetBody", new Type[] {});
                            MethodInfo generic = method.MakeGenericMethod(messageBodyType);
                            var messageBody = generic.Invoke(receivedMessage, null);
                            //Process the message contents           
                            var helper = new Helpers();
                            receivedMessage.RenewLock();
                            helper.ProcessMessage(messageBody);

                            //Everything ok, so take it off the queue
                            receivedMessage.Complete();
                        }
                        catch (Exception ex)
                        {
                            Tracing.Error("[ServiceBusWorker.MessageError] Deadlettering " + ex.Message,
                                TracingLogPartion.Error);
                            receivedMessage.DeadLetter();
                            continue;
                        }
                    }

                }
                catch(Exception e)
                {
                    Tracing.Error("There was an error!" + e.Message, TracingLogPartion.Error);
                    Thread.Sleep(3000);
                    continue;
                }


            }
        }

        public override bool OnStart()
        {

            //azure config
            ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.Http;
            const string connectionString = "Endpoint=sb:/xxxxx"; 
            var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
            if (!namespaceManager.TopicExists(TopicName))
                namespaceManager.CreateTopic(TopicName);

            if (!namespaceManager.SubscriptionExists(TopicName, SubscriptionName))
                namespaceManager.CreateSubscription(TopicName, SubscriptionName);

            _client = SubscriptionClient.CreateFromConnectionString(connectionString, TopicName, SubscriptionName, ReceiveMode.PeekLock);


            //namespaceManager.CreateSubscription(TopicName, SubscriptionName, new SqlFilter("MessageType = 'NOTIFICATION'"));
            IsStopped = false;
            return base.OnStart();
        }

        public override void OnStop()
        {
            // Close the connection to Service Bus Queue
            _client.Close();
            base.OnStop();
        }


        private IContainer BuildKernel(string tenantName)
        {
            var tenantIdStrategy = new StringTenantIdentificationStrategy(tenantName);

            var builder = new ContainerBuilder();

            //Adding the tenant ID strategy into the container
            builder.RegisterInstance(tenantIdStrategy).As<ITenantIdentificationStrategy>();
            builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope();

            //Register Dependencies Shared Accross Tenants
            builder.RegisterModule(new GeographyModule());
            builder.RegisterModule(new ORMModule());
            builder.RegisterModule(new EmploymentModule());
            builder.RegisterModule(new AuthenticationModule());
            builder.RegisterModule(new NotificationsModule());
            builder.RegisterModule(new NationBuilderModule());
            builder.RegisterModule(new CommonModule());
            builder.RegisterModule(new ContributionsModule());
            builder.RegisterModule(new IntakeManagementModule());
            builder.RegisterModule(new StatsModule());
            builder.RegisterModule(new Click2MailModule());
            builder.RegisterModule(new MatchingModule());
            builder.RegisterModule(new ExportModule());
            builder.RegisterModule(new BlueStateDigitalModule());
            builder.RegisterModule(new RevolutionMessagingModule());
            builder.RegisterModule(new TaskSchedulerModule());
            builder.RegisterType<WorkerMessageHandler>().As<IMessageHandler<WorkerUpdateMessage>>();
            builder.RegisterType<IntakeMessageHandler>().As<IMessageHandler<IntakeRecordMessage>>();
            builder.RegisterType<ExportWorkersMessageHandler>().As<IMessageHandler<ExportWorkersMessage>>();
            builder.RegisterType<ExportTurfMessageHandler>().As<IMessageHandler<ExportTurfMessage>>();
            builder.RegisterType<Click2MailMessageHandler>().As<IMessageHandler<Click2MailMessage>>();
            builder.RegisterType<StatsRefreshMessageHandler>().As<IMessageHandler<StatsRefreshMessage>>();

            //Create multitenant container based upon application defaults
            var mtc = new MultitenantContainer(tenantIdStrategy, builder.Build());
            //register all the tenants using helper method in auth project.
            mtc = mtc.RegisterAllTenants();
            return mtc;

        }

    }
}

我正在使用的策略:

    namespace CAR.Authentication.Tenants
{
    //Used to create tenants using worker roles.
    public class StringTenantIdentificationStrategy : ITenantIdentificationStrategy
    {
        private string TenantName { get; set; }
        public StringTenantIdentificationStrategy(string tenantName)
        {
            TenantName = tenantName;
        }

        public bool TryIdentifyTenant(out object tenantId)
        {
            tenantId = GetTenantFromTenantNameString(TenantName);
            return tenantId != null;
        }

        private string GetTenantFromTenantNameString(string hostName)
        {
            var tenants = TenantList.Build();
            var tenant = tenants.SingleOrDefault(p => p.TenantName.Equals(hostName));

            if (tenant == null)
                return null;

            return tenant.TenantName;
        }
    }
}

我想将MultitenantContainer用作Kernel而不是IContainer,然后根据需要调用Kernel.GetTenantScope(tenantId).Resolve<Component>。但是,如果没有租户识别策略,我无法注册MultitenantContainer。

0 个答案:

没有答案