Я использовал код DataContextFactory Рика Страла (Linq to SQL DataContext Lifetime Management). на уровне данных, используемом приложением ASP.Net. Это прекрасно работает, потому что текущий контекст данных хранится в коллекции HttpContext.Items. Я знаю, что повторно использую один и тот же контекст данных для каждого веб-запроса.

Однако мне не удалось успешно использовать фабрику в службе WCF. В приложении, отличном от HttpContext, фабрика сохраняет контекст данных в слоте данных потока.

Thread.AllocateNamedDataSlot(key)

Проблема в том, что независимо от того, как я настроил ConcurrencyMode и InstanceContextMode в своей службе, потоки повторно используются при каждом вызове, и повторно используется один и тот же dataContext. Я не хочу этого. Я хочу, чтобы для каждого вызова метода службы существовал только один контекст данных. Можно ли как-то добиться этого с помощью фабрики? Я не могу найти какую-либо уникальную информацию о каждом вызове клиента для использования в качестве идентификатора для моего контекста данных, поэтому он не будет повторно использоваться другими запросами... независимо от того, является ли это одним и тем же клиентом.

Я хочу использовать свой бизнес-уровень и не обращаться к моему уровню данных напрямую, но я боюсь, что мне, возможно, придется диктовать свои собственные единицы работы и контексты данных в моей службе WCF. Удалось ли кому-нибудь использовать какую-то фабрику для своих контекстов данных в службе WCF? Я надеялся, что у моей фабрики есть способ узнать, используется ли она службой WCF, а затем однозначно обрабатывать хранение контекста данных.

public static T GetScopedDataContext<T>()
{
    if (HttpContext.Current != null)
        return (T)GetWebRequestScopedDataContextInternal(typeof(T), typeof(T).ToString(), null);

    // What can I put here to handle WCF services differently?
    return (T)GetThreadScopedDataContextInternal(typeof(T), typeof(T).ToString(), null);
}

И что тут можно сделать, чтобы добиться желаемого?

static object GetThreadScopedDataContextInternal(Type type, string key, string ConnectionString)
{
    if (key == null)
        key = "__WRSCDC_" + Thread.CurrentContext.ContextID.ToString();

    LocalDataStoreSlot threadData = Thread.GetNamedDataSlot(key);

    object context = null;

    if (threadData != null)
        context = Thread.GetData(threadData);

    if (context == null)
    {
        if (ConnectionString == null)
            context = Activator.CreateInstance(type);
        else
            context = Activator.CreateInstance(type, ConnectionString);

        if (context != null)
        {
            if (threadData == null)
                threadData = Thread.AllocateNamedDataSlot(key);

            Thread.SetData(threadData, context);
        }
    }
    return context;
}
1
Jason Butera 11 Мар 2011 в 19:55

1 ответ

У меня та же проблема. Я использую контейнер Castle.Windsor IOC + образ жизни «PerWebRequest», и он работает так же, как ваша фабрика под капотом.

Я все еще пытаюсь найти идеальное решение для своих нужд, но у меня есть промежуточное решение, которое может вам помочь: заставить вашу службу WCF работать с HttpContext:

1) В вашем проекте WCF запросите совместимость с ASP.Net.

<system.serviceModel>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
</system.serviceModel>

2) Добавьте атрибут к вашему сервису для управления этой совместимостью

[AspNetCompatibilityRequirements(
    RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class MyService : IMyContract
{
  ...
}

Источник : разбор кода

0
Mose 29 Апр 2011 в 18:19