Frage

Ich habe eine Datenzugriffsschicht, eine Service-Schicht und eine Darstellungsschicht. Die Darstellungsschicht ist ASP.NET MVC2 RTM (Web), und der Service Layer ist WCF (Services). Es ist alles .NET 3.5 SP1.

Das Problem ist, dass in den Diensten, die Objekte mit dem [DataContract] Attribute markiert zurückgegeben werden. Die Bahn wird mit dem AppFabric Cache (a.k.a Velocity) SessionStateProvider zum Speichern von Sitzungszustand. Aus diesem Grunde muss alles, was ich Laden in der Sitzung serialisierbar sein.

Hier kommt das Problem: Die Datacontracts nicht mit [Serializable] markiert und soweit ich mich erinnern kann, indem sie auf eine Klasse Einführung bereits mit [DataContract] markierte einige Probleme entstehen, und so glaube ich nicht, das ist eine Lösung.

Ich war zunächst auf die Planung der Datacontracts direkt im Web-Schicht verwendet wird, sie als Modelle zur Verwendung von Ansichten in Bezug auf die Datacontracts Rendering (wahrscheinlich in einem höheren Niveau Ansichtsmodell Klasse verschachtelt). Aber aufgrund der Sitzungsstatus-Provider erfordern alle Objekte darin gespeichert sein serializable, ich fange an, diese Strategie zu überdenken. Es wäre schön, wenn auch zu haben, da sie Validierungslogik mit der IDataErrorInfo-Schnittstelle und die gleiche Validierungslogik könnte enthalten sein wiederverwendet in MVC als Teil des Modells zu binden.

Was glauben Sie ist der beste Weg, mir zu erlauben, die Arbeit benötigt zu reduzieren?

habe ich zur Zeit dacht an den folgenden verschiedenen Möglichkeiten:

A. Erstellen Sie ein 'ServiceIntegration' an der Web-Projekt.

Dies wäre ein mittlerer Mann zwischen meinem Controller und meinem WCF-Service-Layer sein. Der ServiceIntegration Teil der Dienstschicht sprechen würde Datacontracts verwenden und auf die Web-Schicht unter Verwendung von Viewmodels, sondern zwischen den Datacontracts und Viewmodels unter Verwendung eines Zwei-Wege-Transformator zur Transformation haben.

Da auch die IDataErrorInfo Validierung würde nicht wiederverwendbar sein, wäre es notwendig, einen Validator pro Datacontract zu schaffen, dass der Transformator zu konvertieren von Viewmodel zu Datacontract verwendet, führt die Validierung IDataErrorInfo verwenden und ihre Ergebnisse zurück. Dies würde dann in Aktion Methoden des Controller verwendet werden (z.B. if (!MyValidator.IsValid(viewModel)) return View();)

Verschiedene Klassen benötigt: xDataContract, xViewModel, xTransformer, xValidator

B. Erstellen Sie ein 'SessionIntegration' an der Web-Projekt

Dies wäre ein Mitte-Mann zwischen den Controllern (oder irgendetwas Zugriff auf die Sitzung) und die Tagung. Alles, was den Zugriff auf die Sitzung durch diese Klasse gehen würde. Datacontracts würde in der gesamten Anwendung verwendet werden, sofern sie nicht in die Sitzung gespeichert werden. Der SessionIntegration Teil würde die Verantwortung für die Datacontract zu einem gewissen ISerializable Form transformiert, und zurück. Kein zusätzlicher Validator wegen der Verwendung von IDataErrorInfo-Schnittstelle auf der Datacontract benötigt wird.

Verschiedene Klassen benötigt: xDataContract, xTransformer, xSerializableForm


. Hinweis: es noch Viewmodel um in beiden Szenarien wäre jedoch mit (B) I compose von Viewmodel Datacontracts der Lage sein würde

(B) hat den Vorteil, keinen zusätzlichen Validator benötigen.


Bevor ich gehe ab und implementieren (A) / (B) vollständig, würde ich ein Feedback mögen. Im Moment beginne ich in Richtung (B) zu lehnen jedoch (A) könnte flexibler sein. So oder so, wie es scheint, viel zu viel Arbeit für das, was es wert ist. Hat sonst noch jemand über dieses Problem kommt, sind Sie einverstanden / nicht einverstanden mit mir, und / oder haben Sie andere Art und Weise haben, das Problem zu lösen?

Danke,

James

War es hilfreich?

Lösung

Ohne die Blas- Route von A oder B gehen, könnten Sie nur ein generische ISerializable Wrapper-Objekt machen und setzen diese in Ihrer Session?

    [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);   
                }
            }
        }
    }

Andere Tipps

Als Erweiterung zur Verfügung gestellten Antwort, habe ich diese beiden Methoden Speicherung zu erleichtern / die Daten abgerufen werden.

    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);
    }

Das macht es ein wenig einfacher zu setzen / bekommen Werte aus der Sitzung:

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

Um es noch einfacher zu machen, fügen Sie Erweiterungsmethoden:

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);
    }
}

Und Verwendung wie folgt:

    MyDataContract c = ...;
    Session.SetWrapped("mykey", c);
    c = Session.GetWrapped<MyDataContract>("mykey");
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top