Serializacja/deserializacja JSON w C# vs. CRM Sandbox

Dynamics CRM, JSON

Dynamics CRM przenosi się ostatnio do chmury. Na ocenę tego, czy ma to sens, przyjdzie czas w przyszłości (osobiście mam w tym momencie bardzo mieszane odczucia, zwłaszcza w kontekście umieszczania w chmurze aplikacji XRM).

Programiści zajmujący się tą platformą zdają sobie bez wątpienia sprawę z tego, że biblioteki .NET, rozszerzające funkcjonalność systemu możemy uruchomić w chmurze jedynie w trybie „piaskownicy” („sandbox mode”). Niestety Microsoft dość enigmatycznie i w mało szczegółowy sposób opisuje to, na co omawiany tryb pozwala.

Zderzyłem się ostatnio w pracy z tematem serializacji (a właściwie deserializacji) danych w formacie JSON z poziomu kodu C# rozszerzającego funkcjonalność CRM (CRM Plugin). Poniższe punkty opisują klasyczną „drogę samuraja”, która doprowadziła do pomyślnej realizacji tego tematu.

Wykorzystujemy zewnętrzną bibliotekę, czyli znane i lubiane JSON.NET

Pomysł umarł zanim właściwie się narodził. Każdy, kto choć raz próbował korzystać w CRM On-Line z zewnętrznych bibliotek wie, że z uwagi na architekturę rozwiązania jest to proces wybitnie problematyczny i nie zawsze gwarantujący sukces. Na zabawę z narzędziami w rodzaju ILMerge lub Fody/Costura z uwagi na późniejsze trudności z utrzymaniem i rozwijaniem rozwiązania nie miałem czasu ani ochoty.

W związku z powyższym uznałem, że na zabawę z JSON.NET przyjdzie czas w innym projekcie. Sorry NewtonSoft…

A może tak JavaScriptSerializer?

 

JavaScriptSerializer js = new System.Web.Script.Serialization.JavaScriptSerializer();
Dictionary<string, string> input = js.Deserialize<Dictionary<string, string>>(this.my_entity.my_input); // deserialize

W środowisku developerskim (on-premise) powyższy fragment kodu działał bez zarzutu. Niestety próba uruchomienia go w mitycznej chmurze zakończyła się następującym komunikatem:

Assembly ‚System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’ is a conditionally APTCA assembly which is not enabled in the current AppDomain.  To enable this assembly to be used by partial trust or security transparent code, please add assembly name ‚System.Web.Extensions, PublicKey=0024000004800000940000000602000000240000525341310004000001000100B5FC90E7027F67871E773A8FDE8938C81DD402BA65B9201D60593E96C492651E889CC13F1415EBB53FAC1131AE0BD333C5EE6021672D9718EA31A8AEBD0DA0072F25D87DBA6FC90FFD598ED4DA35E44C398C454307E8E33B8426143DAEC9F596836F97C8F74750E5975C64E2189F45DEF46B2A2B1247ADC3652BF5C308055DA9’ to the the PartialTrustVisibleAssemblies list when creating the AppDomain.

This assembly is marked as conditionally APTCA (allow partially trusted callers attribute), which means that code running in the Sandbox won’t be able to call into it without product changes to CRM. Without this change, there isn’t a supported workaround.

Czyli: „Ch…, d… i kamieni kupa.”, cytując pewnego Pana, zasiadającego do niedawna w rządowych ławach.

Sukces!!!

using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(OpportunityCloseDetails));
OpportunityCloseDetails input = jsonSerializer.ReadObject(dataStream) as OpportunityCloseDetails;

Powyższy kod w końcu daje się uruchomić i działa w środowisku on-line. Uważajcie tylko widoczność klasy, która stanowi w powyższym scenariuszu kontrakt. W omawianym przykładzie będzie to klasa „OpportunityCloseDetail”.

[DataContract]
public class OpportunityCloseDetail
{
   [DataMember]
   public string StatusReason;

    [DataMember]
    public string CompetitorId;

    [DataMember]
    public string CloseDate;

    [DataMember]
    public string Description;
}

Powyższa klasa wraz z jej wszystkimi atrybutami musi być zdefiniowana, jako publiczna. Inaczej ponownie zostaniemy wyrzuceni z piaskownicy. Chociaż o tym dokumentacja akurat wyjątkowo wspomina :).

Total Views: 1544 ,