ASMX JSON сериализация против WCF JSON сериализации - PullRequest
1 голос
/ 24 ноября 2011

У меня есть два экспериментальных веб-сервиса. Одним из них является asmx, содержащийся в веб-приложении .net. Другая - это библиотека служб WCF, вызываемая из веб-приложения.

Asmx в основном делает все, что мне нужно, но я думаю, что WCF был бы лучше, за исключением того, что он ничего не делает, как я ожидал бы после возиться со службой asmx.

Например, один и тот же метод ведет себя по-разному в каждом:

' ASMX
<WebMethod(BufferResponse:=True, EnableSession:=False)>
Function Test(aObject as Object) as Object
  ' object will have been successfully serializaed into a dictionary
  Dim lResult as SomeObject = new SomeObject(aObject)
  return lResult ' lResult will be serialized as whatever type it is and will be deserialized by client making ajax call
End Function

' WCF
<OperationContract()>
<WebInvoke(RequestFormat:=ServiceModel.Web.WebMessageFormat.Json,
           ResponseFormat:=ServiceModel.Web.WebMessageFormat.Json,
           BodyStyle:=WebMessageBodyStyle.Wrapped)>
Function Test(aObject As Object) As Object
  ' object is serialized as an empty instance of Object
  ' not very useful
  Dim lResult as SomeObject = new SomeObject(aObject) ' waste of time with useless object
  return lResult ' even if lResult could be instantiated the client returns error 500 because 
                 ' WCF won't serialize SomeObject as Object
End Function

Я исследовал эту проблему время от времени, так как у меня есть время между проектами. Ничто из того, что я пробовал, не заставляет WCF делать то, что делает ASMX. Есть идеи?

Ответы [ 3 ]

1 голос
/ 30 ноября 2011

Мы добавили функцию, которая возвращает все типы, включая List (of T) для каждого типа, которые соответствуют нашим желаемым критериям - объекты, которые могут храниться в нашем кэше. Пока мы помечаем типы ICacheable в нашей сборке * .Core с помощью IsCacheableAttribute, они будут возвращаться в списке, и нам не нужен жестко закодированный список KnownType, который невозможно поддерживать. Мы также добавили свойство d для хранения данных, которое, как мы надеемся, делает то же самое для безопасности в браузере / клиенте, который делает Microsoft .d.

Imports System.Reflection
Imports OurCompany.Cache
Imports OurApplication.Core

<DataContract(), KnownType("AllTypes")>
Public Class Data

    Private Shared mCacheableType As Type = GetType(ICacheable)
    Private Shared mIsCachedAttribute As Type = GetType(IsCacheableAttribute)

    <DataMember()>
    Public Property d As Object

    Private Shared Function AllTypes() As IEnumerable(Of Type)
        Return GetCacheableTypesFromAssembly(GetType(AssemblyKeyClass).Assembly)
    End Function

    Private Shared Function GetCacheableTypesFromAssembly(aAssembly As Assembly) As IEnumerable(Of Type)
        Dim lTypes As List(Of Type) = aAssembly.GetTypes().Where(Function(t) IsCacheable(t)).ToList
        Dim lTypes2 As List(Of Type) = New List(Of Type)
        lTypes2.AddRange(lTypes)
        For Each lType In lTypes2
            Dim lListType As Type = GetType(List(Of )).MakeGenericType({lType})
            lTypes.Add(lListType)
        Next
        Return lTypes
    End Function

    Private Shared Function IsCacheable(aType As Type) As Boolean
        Dim lResult As Boolean = False
        If aType.GetInterfaces.Contains(mCacheableType) Then
            Dim lAttribute As Object() = aType.GetCustomAttributes(mIsCachedAttribute, True)
            If lAttribute.Count = 1 Then
                lResult = DirectCast(lAttribute(0), IsCacheableAttribute).Value
            End If
        End If
        Return lResult
    End Function

End Class

Вот метод IService, который мы использовали для проверки возврата различных типов данных.

<OperationContract()>
<WebInvoke(RequestFormat:=ServiceModel.Web.WebMessageFormat.Json,
           ResponseFormat:=ServiceModel.Web.WebMessageFormat.Json,
           BodyStyle:=WebMessageBodyStyle.Bare)>
Function Test() As Data

Что касается передачи данных в службу, мы просто будем придерживаться передачи строки и использования JavaScriptSerializer для ее десериализации. Таким образом мы сохраняем поведение «неизвестный объект в словарь», на которое рассчитываем для некоторых сложных типов.

1 голос
/ 02 декабря 2011

Незначительные изменения устраняют связь с пространством имен приложения и позволяют нам использовать этот класс как часть нашей коллекции базовых библиотек.Мы превратили данные в универсальный тип.Это наверняка лучше, чем набирать KnownType (GetType (YetAnotherClass)) сотни раз, а затем каждый раз, когда мы добавляем в систему новый переносимый класс json.

<DataContract(), KnownType("AllTypes")>
Public NotInheritable Class Data(Of T)

    Private Shared Function AllTypes() As IEnumerable(Of Type)
        Return GetSerializableTypesFromAssembly(GetType(T).Assembly)
    End Function
1 голос
/ 24 ноября 2011

Я вижу, что вы создаете сервисы WCF для конкретного контракта интерфейса.

Если вы можете просто указать любой тип объекта, то не существует программного механизма для проверки того, что любой конец канала правильно реализовал этот интерфейс.

Я обнаружил, что WCF, как правило, гораздо более строг, чем ASMX, с точки зрения сериализации и десериализации классов, но переход на WCF с ASMX значительно улучшил наши приложения с точки зрения стабильности, удобства обслуживания и производительности.

Сказав это, нет причин переходить на WCF только потому, что это WCF. Вам нужно точно определить, почему вы считаете, что это лучше для вашей ситуации, и, если это так, то вам нужно создать несколько тестовых случаев, используя реальные классы, а не просто Objects, чтобы убедиться, что он будет соответствовать вашим потребностям.

Стоит задуматься: если вы используете сервисы WCF в своих собственных .Net-приложениях, написанных на Silverlight, WPF или WinForms, то в конечном итоге WCF значительно облегчит вашу жизнь, так как позволяет делиться один и тот же код класса бизнес-объекта на обоих концах канала.

Обновление с информацией из комментариев

На самом деле, вы можете сериализовать абстрактные классы, если они могут быть десериализованы в конкретные реализации. Вы можете сделать это, присвоив абстрактный класс атрибуту KnownType для каждого конкретного класса, который вы хотите сериализовать.

Основная проблема не в контракте интерфейса службы, а в DataContract, который требует определенного класса в какой-то момент. Эта ссылка описывает правила.

Вы можете создать класс catchall, который наследуется от объекта и имеет известный тип для классов, которые вы хотите использовать.

...