Использование DataContrattratt WCF в SessionSate MVC с использованием AppFabric Cache

StackOverflow https://stackoverflow.com/questions/3612243

Вопрос

У меня есть уровень доступа к данным, сервисный слой и слой презентации. Слой презентации представляет собой ASP.NET MVC2 RTM (WEB), а сервисный слой является WCF (услуги). Это все .NET 3.5 SP1.

Проблема в том, что в сервисах возвращаются объекты, отмечены [DataContract] атрибут. Веб использует сеанс SESSICSTATEPADER CACHE (AKA VELOCITY) для хранения состояния сеанса. Благодаря этому, все, что я храним в сеансе, должен быть сериализуемым.

Вот проблема: DataContracts не отмечены [Serializable] И насколько я могу вспомнить, введя его на класс, уже отмеченный [DataContract] Некоторые проблемы возникают, и поэтому я не верю, что это решение.

Первоначально я был планировал использовать DataContracts прямо в веб-слое, используя их в виде моделей для представлений, связанных с рендерингом данных DataContracts (вероятно, вложенные внутри класса ViewModel Review Models). Но благодаря провайдеру государства заседаний, требующих всех объектов, хранящихся внутри него, чтобы быть сериализуемым, я начинаю переосмыслить эту стратегию. Было бы неплохо иметь, так как они содержат логику валидации, используя IDataErrorInfo Интерфейс, а та же самая логика валидации может быть повторно использована в MVC как часть моделей связывания.

Что вы считаете лучшим способом позволить мне уменьшить необходимую работу?

Я сейчас думал о следующих разных отношениях:

A. Создайте часть «Сервистеграция» в веб-проекте.

Это будет средний человек между моими контроллерами и моим уровнем обслуживания WCF. Сервисная часть будет говорить с сервисным слоем с использованием Datacontracts, а также к веб-слою с использованием ViewModels, но придется преобразовать между DataContracts и ViewModels, используя двусторонний трансформатор.

Кроме того, поскольку проверка IDATAERRINFO не будет повторно использоваться, необходимо будет также создать валидатор на DataContract, что использует трансформатор для преобразования от ViewModel в Datacontratt, выполните проверку, используя IDATATATARRINFO и вернуть его результаты. Это будет использоваться внутри методов действия контроллеров (например, if (!MyValidator.IsValid(viewModel)) return View();)

Требуется разные классы: xdatacontratt, xviewmodel, xtransformer, xvalidator

B. Создайте часть «рассеяния» в веб-проекте

Это было бы средним человеком между контроллерами (или что-либо доступа к сеансу) и сама сеанса. Все, что требует доступа к сеансу пройдет через этот класс. DataContracts будут использоваться во всем приложении, если они не хранятся в сеансе. Часть сессионной интергревации не несет ответственности за преобразование DataContratt в некоторую изиселюализируемую форму и обратно. Никакой дополнительной валидатора не требуется из-за использования интерфейса IDATAERRORINFO на DataContratt.

Требуется разные классы: xdatacontract, xtransformer, xserializableform


ПРИМЕЧАНИЕ. В обоих сценариях все равно будет просмотреть модерты в обоих сценариях.

(B) имеет преимущество не нуждающегося в дополнительном валидатере.


Прежде чем уйти и внедрить (а) / (б) полностью, я хотел бы получить некоторые отзывы. На данный момент я начинаю опираться на (b), однако (а) может быть более гибким. В любом случае, это кажется слишком много работы для того, что она стоит. Кто-нибудь еще встречается с этой проблемой, вы согласны / не согласны со мной, и / или у вас есть какой-либо другой способ решения проблемы?

Спасибо,

Джеймс

Это было полезно?

Решение

Не собирая полноценный маршрут A или B, не могли бы вы просто сделать общий объект изисереализируемой обертки и поместите те, которые в вашей сессии?

    [Serializable]
    public class Wrapper : ISerializable
    {
        public object Value { get; set; }

        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (Value != null)
            {
                info.AddValue("IsNull", false);
                if (Value.GetType().GetCustomAttributes(typeof(DataContractAttribute), false).Length == 1)
                {
                    using (var ms = new MemoryStream())
                    {
                        var serializer = new DataContractSerializer(Value.GetType());
                        serializer.WriteObject(ms, Value);
                        info.AddValue("Bytes", ms.ToArray());
                        info.AddValue("IsDataContract", true);
                    }
                }
                else if (Value.GetType().IsSerializable)
                {
                    info.AddValue("Value", Value);
                    info.AddValue("IsDataContract", false);
                }
                info.AddValue("Type", Value.GetType());
            }
            else
            {
                info.AddValue("IsNull", true);
            }
        }

        public Wrapper(SerializationInfo info, StreamingContext context)
        {
            if (!info.GetBoolean("IsNull"))
            {
                var type = info.GetValue("Type", typeof(Type)) as Type;

                if (info.GetBoolean("IsDataContract"))
                {
                    using (var ms = new MemoryStream(info.GetValue("Bytes", typeof(byte[])) as byte[]))
                    {
                        var serializer = new DataContractSerializer(type);
                        Value = serializer.ReadObject(ms);
                    }
                }
                else
                {
                    Value = info.GetValue("Value", type);   
                }
            }
        }
    }

Другие советы

В качестве расширения до предоставленного ответа я добавил эти два способа для облегчения хранения / извлечения данных.

    public static void Set<T>(HttpSessionStateBase session, string key, T value)
    {
        session[key] = new Wrapper(value);
    }

    public static T Get<T>(HttpSessionStateBase session, string key)
    {
        object value = session[key];
        if (value != null && typeof(T) == value.GetType())
        {
            return (T) value;
        }
        Wrapper wrapper = value as Wrapper;
        return (T) ((wrapper == null) ? null : wrapper.Value);
    }

Это делает его немного легче установить / получить значения с сеанса:

    MyDataContract c = ...;
    Wrapper.Set(Session, "mykey", c);
    c = Wrapper.Get<MyDataContract>(Session, "mykey");

Чтобы сделать его еще проще, добавьте методы расширения:

public static class SessionWrapperEx
{
    public static void SetWrapped<T>(this HttpSessionStateBase session, string key, T value)
    {
        Wrapper.Set<T>(session, key, value);
    }

    public static T GetWrapped<T>(this HttpSessionStateBase session, string key)
    {
        return Wrapper.Get<T>(session, key);
    }
}

И использовать как ниже:

    MyDataContract c = ...;
    Session.SetWrapped("mykey", c);
    c = Session.GetWrapped<MyDataContract>("mykey");
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top