Question

Il y a quelques jours, j'ai eu un problème avec le filetage ASP.Net. Je voulais avoir un objet singleton par requête web. J'ai réellement besoin pour mon unité de travail. Je voulais instancier une unité de travail par requête web de sorte que la carte d'identité est valable par la demande. De cette façon, je pouvais utiliser un IoC pour injecter mon propre IUnitOfWork à mes cours référentiel de manière transparente, et je pouvais utiliser la même instance pour interroger puis mettre à jour mes entités.

Depuis que je suis en utilisant l'unité, je tort utilisé PerThreadLifeTimeManager. Je me suis vite rendu compte que le modèle de filetage ASP.Net ne supporte pas ce que je veux atteindre. Fondamentalement, il utilise un threadpool et recycle des fils, et cela signifie que je reçois un UnitOfWork par fil !! Cependant, ce que je voulais était une unité de travail par requête web.

Un peu de googler m'a donné ce grand message . C'était exactement ce que je voulais; sauf pour la partie de l'unité qui était assez facile à réaliser.

Ceci est ma mise en œuvre pour l'unité PerCallContextLifeTimeManager:

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()
    {
    }
}

Et bien sûr, je l'utiliser pour enregistrer mon unité de travail avec un code similaire à ceci:

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

Je espère que ça sauve quelqu'un un peu de temps.

Était-ce utile?

La solution

Neat solution, mais chaque instance de LifetimeManager devrait utiliser une clé unique plutôt qu'une constante:

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

Sinon, si vous avez plus d'un objet enregistré avec PerCallContextLifeTimeManager, ils sont le partage de la même clé pour accéder CallContext, et vous ne serez pas récupérer votre objet attendu.

Il convient également de mettre en œuvre removeValue pour assurer les objets sont nettoyés:

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

Autres conseils

Bien que ce soit bien appeler cette PerCallContextLifeTimeManager, je suis sûr que c'est pas « sûr » pour être considéré comme un ASP.Net LifeTimeManager par demande.

Si ASP.Net fait son thread-échange alors la seule chose prise à travers le nouveau fil à travers CallContext est le HttpContext actuel - tout ce que vous stockez dans CallContext sera parti. Cela signifie que sous une lourde charge le code ci-dessus pourrait avoir des résultats inattendus - et j'imagine que ce serait une vraie douleur pour traquer pourquoi

La seule façon de le faire est avec HttpContext.Current.Items, ou faire quelque chose comme « sûr »:

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()
    {
    }
}

Cela signifie évidemment prendre des dépendances sur System.Web: - (

Beaucoup plus d'informations sur ce disponibles à:

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

Merci pour votre contribution,

Mais la question la mise en œuvre proposée présente deux inconvénients, dont l'un est un bogue sérieux comme cela a déjà déclaré Steven Robbins dans sa réponse et Micah Zoltu dans un commentaire .

  1. contexte d'appel n'est pas garanti d'être préservés par Asp.Net pour une seule requête. Sous charge, il peut passer à un autre, ce qui provoque la mise en œuvre proposée à briser.
  2. Il ne gère pas la libération des dépendances à la fin de la demande.

À l'heure actuelle, package Unity.Mvc Nuget fournit un PerRequestLifetimeManager pour faire le travail. Ne pas oublier d'enregistrer son UnityPerRequestHttpModule associé au code bootstrapping dépendances ne diffusent être traitées non plus.

Utilisation bootstrapping

DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));

ou en system.webServer/modules web.config

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

Il apparaît sa mise en œuvre actuelle est également adapté pour les formulaires Web. Et il ne dépend même pas sur MVC. Malheureusement, son assemblée fait, à cause de quelques autres classes qu'il contient.

Méfiez-vous, au cas où vous utilisez certains module http personnalisé à l'aide de vos dépendances résolues, ils peuvent déjà être disposés dans le module EndRequest. Cela dépend de l'ordre d'exécution du module.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top