Получите доступ к текущему экземпляру Context в WCF UserNamePasswordValidator
-
27-09-2020 - |
Вопрос
У меня есть служба WCF, которая использует пользовательский UserNamePasswordValidator.Валидатору необходимо получить доступ к контексту моей entity framework.
Я хотел бы создать один ObjectContext для всего вызова службы, а затем уничтожить / утилизировать его в конце вызова.Итак, я создал статический класс singleton, который предоставлял эту функциональность, однако сейчас происходит то, что если два вызова службы происходят одновременно, один из вызовов удаляет синглтон.
Я либо сохраняю локальную ссылку на ObjectContext, и в этом случае вторая служба, использующая его, видит его как удаленный и выдает ошибку, либо я помещаю свойство-оболочку вокруг класса Singleton везде, где мне это нужно, и тогда все мои изменения отбрасываются, потому что я получаю новый экземпляр класса Singleton. объект, если другой вызов удалил его.
Итак, в основном мой вопрос заключается в том, как мне создать экземпляр ObjectContext для каждого вызова службы?
записка:Экземпляр должен быть доступен как в служебном коде, так и в пользовательском коде UserNamePasswordValidator.
Я не могу просто сделать это в конструкторе или использовать оператор using, потому что тогда пользовательский UserNamePasswordValidator не имеет к нему доступа.Есть ли способ создать статический класс для каждого вызова?Это действительно звучит невозможно, но как это можно обойти?Должен ли я кэшировать объект в сеансе?
Мой сервис размещен в IIS.
ОБНОВЛЕНИЕ:
Итак, я свел это к сохранению состояния в InstanceContext, используя объект IExtension.Но как мне получить доступ к текущему InstanceContext в UserNamePasswordValidator?
Решение
ОК, поэтому в конце я решил его, используя следующий статический класс и полагаясь на ASP.NET, чтобы кэшировать контекст для меня.
Я не уверен, что это лучший способ сделать вещи, но это позволяет мне использовать один объектContext на запрос, поэтому я не спирал слишком много, и это также означает, что мне не нужно использовать замокНа объекте, который стал бы кошмаром, если многие пользователи использовали сервис.
public static class MyContextProvider
{
public static MyModel Context
{
get
{
if (HttpContext.Current.Items["context"].IsNull())
{
HttpContext.Current.Items["context"] = new MyModel();
}
return HttpContext.Current.Items["context"] as MyModel;
}
}
}
.
Тогда везде, где мне нужен объектContext в приложении, я просто звоню
var context = MyContextProvider.Context;
. Другие советы
У вас есть один экземпляр на вызов, у вас также есть 1 вызов на экземпляр.
Таким образом, это должно быть очень просто, используйте using () { }
заблокируйте на верхнем уровне вашего метода OperationContract.
OK, вот класс с безопасным статическим методом, который предоставляет один объект модели объекта ObjectContext для любого вызова службы WCF и автоматически располагается его в конце вызова:
public static class EntityModelProvider
{
private static readonly Dictionary<OperationContext, MyEntityModel> _entityModels = new Dictionary<OperationContext, MyEntityModel>();
public static MyEntityModel GetEntityModel()
{
if (OperationContext.Current == null)
throw new Exception("OperationContext is missing");
lock (_entityModels)
{
if (!_entityModels.ContainsKey(OperationContext.Current))
{
_entityModels[OperationContext.Current] = new MyEntityModel();
OperationContext.Current.OperationCompleted += delegate
{
lock (_entityModels)
{
_entityModels[OperationContext.Current].Dispose();
_entityModels.Remove(OperationContext.Current);
}
};
}
return _entityModels[OperationContext.Current];
}
}
. Для вашего сервиса вы можете указать поведение службы, которое детализирует режим экземпляра службы:
[ServiceBehaviour(InstanceContextMode = InstanceContextMode.PerCall)]
public class MyService : IMyService {
ObjectContext context;
}
. Очиститель может заключаться в том, чтобы использовать сервисную связь, который находится в .NET 4.
http://msdn.microsoft.com/ru -US / Library / System.ServiceModel.serviceauthenticationmanager.aspx
от метода Authenticate
(который вы переопределите), вы можете получить доступ к объекту сообщения и установить его на свойствах. Я не использовал это в гневе, так что YMMV :)
Отредактируйте проблему с таким подходом - это то, что у вас нет имени пользователя и пароля, поэтому все равно понадобится пользовательская аутентификация.
Посмотрите на usernamesecurityTokenauthenticator ... http:// msdn .microsoft.com / en-us / library / system.identitymodel.selectors.usernamesecurityTokenauthenticator (v= vs.90) .aspx
Дальнейшее чтение из моих исследований:
Ответы на этот вопрос дает некоторые намеки о том, как его использовать:
Пользовательская аутентификация WCF с System.servicemodel.ServiceAuthenticanmanager? / P >.
Если вы можете прочитать (или игнорировать) русский, я нашел полезные советы по адресу:
http://www.sql.ru/forum/actualThread.aspx ? TID= 799046
Это довольно хорошая артикул CodeProject идет дальше (шифрование и сжатие, а также пользовательское разрешение)
http://www.codeProject .com / starles / 165844 / wcf-client-server-application-с-custom-atugeti
Почему бы не пройти в контексте в ваш substlevalidator, когда вы назначаете на сервис - сохраните свой объект контекста в валидатере, а в разделе «Переопределенный метод проверки», если это необходимо.Тогда у вас все еще есть доступ к объекту через службы CutomusernameValidator ..
В зависимости от того, что вы спрашиваете: Создайте свой отдельный класс ObjectContext в качестве динамического объекта - добавьте это в качестве свойства для вас AuStryValidator. В вашем пользовательском валидатере - теперь вы можете проверить, будет ли объект расположен и снова создать объект, если это необходимо. В противном случае, если это не то, что вы после того, как вы, просто храните контекст в Validator - у вас все еще есть доступ на стороне сервера. Кодекс здесь просто обобщенная идея - я просто размещаю его как кадр отсчета, чтобы вы могли иметь представление о том, о чем я говорю.
public DynamicObjectContextObjectClass
{
ObjectContext internalObjectContext;
}
public class ServiceUserNamePasswordValidator : UserNamePasswordValidator
{
public DynamicObjectContextObjectClass dynamiccontext;
public override void Validate(string userName, string password)
{
if(dynamiccontext.internalObjectContext.isdisposed)
{
dynamiccontext.internalObjectContext = new Context;
}
try
{
if (string.IsNullOrEmpty(userName) || password == null)
{
//throw new ArgumentNullException();
throw new FaultException("Username cannot be null or empty; Password cannot be null and should not be empty");
}
}
}
}
.