Pergunta

Alguns dias atrás, eu tive um problema com ASP.Net threading. Eu queria ter um objeto singleton por solicitação da web. Eu realmente preciso disso para minha unidade de trabalho. Eu queria instanciar uma unidade de trabalho por solicitação da web de modo que o mapa de identidade é válido durante todo o pedido. Dessa forma eu poderia usar um IoC para injetar meu próprio IUnitOfWork para minhas aulas de repositório de forma transparente, e eu poderia usar a mesma instância de consulta e, em seguida, atualizar meus entidades.

Desde que eu estou usando Unity, eu erroneamente usado PerThreadLifeTimeManager. Logo percebi que o modelo ASP.Net rosqueamento não suporta o que eu quero alcançar. Basicamente ele usa um pool de threads e recicla tópicos, e isso significa que eu recebo um UnitOfWork por thread !! No entanto, o que eu queria era uma unidade de trabalho por solicitação da web.

Um pouco de googling me deu este grande post . Isso era exatamente o que eu queria; exceto a parte da unidade que foi bastante fácil de conseguir.

Esta é a minha implementação para PerCallContextLifeTimeManager pela unidade:

public class PerCallContextLifeTimeManager : LifetimeManager
{
    private const string Key = "SingletonPerCallContext";

    public override object GetValue()
    {
        return CallContext.GetData(Key);
    }

    public override void SetValue(object newValue)
    {
        CallContext.SetData(Key, newValue);
    }

    public override void RemoveValue()
    {
    }
}

E, claro, eu uso isso para registrar minha unidade de trabalho com um código semelhante a este:

unityContainer
            .RegisterType<IUnitOfWork, MyDataContext>(
            new PerCallContextLifeTimeManager(),
            new InjectionConstructor());

Hope ele salva alguém um pouco de tempo.

Foi útil?

Solução

solução elegante, mas cada instância de LifetimeManager deve usar uma chave única, em vez de uma constante:

private string _key = string.Format("PerCallContextLifeTimeManager_{0}", Guid.NewGuid());

Caso contrário, se você tiver mais de um objeto registrado com PerCallContextLifeTimeManager, eles estão compartilhando a mesma chave para o acesso CallContext, e você não vai ter a sua volta objeto esperado.

Também vale a pena implementar RemoveValue para garantir objetos são limpas:

public override void RemoveValue()
{
     CallContext.FreeNamedDataSlot(_key);
}

Outras dicas

Enquanto isso é bom chamar este PerCallContextLifeTimeManager, eu tenho certeza que isso é não "seguro" para ser considerado um ASP.Net Per-request LifeTimeManager.

Se ASP.Net faz o seu fio-swap, em seguida, o única coisa tomada em todo o novo fio através CallContext é o atual HttpContext - alguma coisa que você armazenar no CallContext será ido. Este meio sob carga pesada o código acima poderia ter resultados indesejados - e eu imagino que seria uma verdadeira dor de rastrear porque

A única maneira "segura" de fazer isso é com HttpContext.Current.Items, ou fazendo algo como:

public class PerCallContextOrRequestLifeTimeManager : LifetimeManager
{
    private string _key = string.Format("PerCallContextOrRequestLifeTimeManager_{0}", Guid.NewGuid());

    public override object GetValue()
    {
      if(HttpContext.Current != null)
        return GetFromHttpContext();
      else
        return GetFromCallContext();
    }

    public override void SetValue(object newValue)
    {
      if(HttpContext.Current != null)
        return SetInHttpContext();
      else
        return SetInCallContext();
    }

    public override void RemoveValue()
    {
    }
}

Isto significa, obviamente, tomar dependências em System.Web: - (

Muito mais informações sobre esta disponível em:

http://piers7.blogspot.com/2005/11/ threadstatic-CallContext-and_02.html

Obrigado por sua contribuição,

Mas a questão de implementação proposto tem duas desvantagens, uma das quais é um bug sério como já foi dito por Steven Robbins em sua resposta e Micah Zoltu em um comentário .

    contexto
  1. Chamada não é garantido para ser preservado por Asp.Net para um único pedido. Sob carga, pode mudar para outra, causando implementação proposta para quebrar.
  2. Não lidar com liberação de dependências a pedido final.

Atualmente, Unity.Mvc Nuget pacote fornece uma PerRequestLifetimeManager para fazer o trabalho. Não se esqueça de registrar seu UnityPerRequestHttpModule associada em bootstrapping código de outra forma dependências liberando não serão tratadas também.

Usando bootstrapping

DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));

ou em web.config system.webServer/modules

<add name="UnityPerRequestHttpModule" type="Microsoft.Practices.Unity.Mvc.UnityPerRequestHttpModule, Microsoft.Practices.Unity.Mvc" preCondition="managedHandler" />

Parece sua implementação atual também é adequado para formulários web. E nem sequer dependem MVC. Infelizmente, sua montagem faz, por causa de algumas outras classes que ele contém.

Cuidado, no caso de você usar algum costume http módulo usando suas dependências resolvidas, eles podem ser já dispostos no EndRequest módulo. Depende de ordem de execução módulo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top