SilverCRM cz. 3 – kilka aspektów związanych z komunikacją Silverlight i CRM

Część druga projektu SilverCRM zakończyła się wspomnieniem na temat aspektów związanych z komunikacją pomiędzy komponentem Silverlight a CRM. Aby je opisać trzeba zrozumieć różnicę pomiędzy np. stronami *.aspx, które wbudowane są w formatkę CRM i znajdują się na serwerze IIS w katalogu ISV. Strony takie uruchamiane są po stronie IIS a klient (czyli przeglądarka) dostaje efekt pracy wykonanej po stronie serwera. Całe wykonanie kodu leży po stronie serwera. W przypadku komponentu Silverlight sprawa wygląda nieco inaczej. To, że znajduje się on na serwerze IIS w tej samej lokalizacji jak strona *.aspx jest jedyną ich cechą wspólną. Wykonanie kodu w przypadku komponentu jest przeniesione na maszynę klienta, tam następuje wykonanie kodu i jednocześnie prezentacja wyniku. Z jednej strony serwer IIS jest odciążony od obsługi dużej ilości żądań a z drugiej strony nasz komponent rozprzestrzenił się po wszystkich stacjach klienckich, które z niego korzystały.

W przypadku usług, z którymi komponent będzie się łączyć może wystąpić problem komunikacji cross-domain. Polega on na tym, że usługa może znajdować się w innej domenie niż nasz komponent, a wtedy wykonanie naszego kodu zakończy się błędem. Rozwiązaniem tego problemu jest umieszczenie po stronie usługi pliku, w którym należy wyspecyfikować, z którym domen usługa powinna obsługiwać żądania. Plik ten musi być nazwany clientaccesspolicy.xml i znajdować się w musi w katalogu głównym naszej usługi. Przykład takiego pliku jest następujący:

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="SOAPAction">
        <domain uri="*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

W tym pliku mamy zezwolenie na łączenie się do usługi z dowolnej domeny: <domain uri="*"/>. Zamiana tego elementu powoduje zezwolenie na łączenie się ze wskazanej domeny. Można również skorzystać z pliku crossdomain.xml, który znany jest chociażby z Flash – na ten temat można znaleźć informacje tutaj: http://msdn.microsoft.com/en-us/library/cc197955(VS.95).aspx

Kolejnym aspektem jest korzystanie z metod usługi CRM. Jak już możemy się z nią odpowiednio komunikować możemy np. pobrać wszystkie konta, do których mamy prawo. Kod, który to zrobi wygląda tak:

QueryExpression _query = new QueryExpression();
_query.ColumnSet = new AllColumns();
_query.EntityName = "account";
_client.RetrieveMultipleAsync(_query);

Jednakże jak się okazuje, mimo, że kolekcja zawiera odpowiednią liczbę elementów o tyle elementy te mają wszystkie właściwości ustawione na null. Błąd ? Z tego co wyczytałem na forach jest to błąd Silverlight, który powinien zostać wyeliminowany, ale z tego co widać jeszcze nie został. Na szczęście jest tzw. workaround. Zamiast pisać krótki kod do pobierania elementów trzeba zawsze pobierać elementy w postaci DynamicEntity. Wtedy dostając się do kolekcji właściwości otrzymamy dane, które nie będą null.

RetrieveMultipleRequest _request = new RetrieveMultipleRequest();
_request.Query = _query;
_request.ReturnDynamicEntities = true;
_client.ExecuteAsync(_request);

Na szczęście tworząc nowe obiekty w CRM, np. nowe konto nie musimy tworzyć obiektu w postaci DynamicEntity tylko możemy korzystać z bezpośrednich klas.

Mając wiedzę z trzech wpisów, które tutaj zamieściłem każdy będzie mógł zacząć tworzyć to, na co jego biznes ma ochotę. Mając do dyspozycji Silverlight można w CRM wbudować bardzo bogato wyglądające elementy, np. piękne raporty, strumieniowanie - jednym słowem wszystko to co oferuje Silverlight.

CRM 4.0 Sharepoint Connector

 

Czasami jest potrzebne w czasie wdrożenia systemu CRM zintegrowanie systemu z bibliotekami dokumentów czy to na darmowym WSS czy też na MOSS. Na podstawie naszego doświadczenia przygotowaliśmy specjalny komponent, który w prosty sposób zastosować można do takiej integracji.

Przy jego pomocy można, m.in:

  1. Tworzyć strukturę katalogów odpowiadającą obiektom w systemie CRM, np. dla każdego klienta tworzymy katalog na dokumenty, dla każdej oferty tworzymy katalog w katalogu klienta na kolejne wersje dokumentu zawierającą aktualną wersję oferty, itd.
  2. Prezentować zawartość katalogu, np. na formatce klienta, na formatce szansy sprzedaży
  3. Automatycznie zarządzać zabezpieczeniami katalogu na WSS tak aby ten kto nie może widzieć rekordów w CRM nie mógł ich znaleźć na katalogu w bibliotece dokumentów.
  4. Automatycznie usuwał katalog w czasie usunięcia rekordu w systemie CRM.

‘…’ oznacza, że komponent ten może działać w dowolny inny sposób jaki sobie tylko zażyczysz :)

Nowy obraz

Wszelkie informacje jak się z nami skontaktować, aby otrzymać szczegółowe informacje dotyczące tego komponentu znaleźć można na stronie: www.netwise.pl

SilverCRM cz. 2 – połączenie z Dynamics CRM.

Silverlight, aby spełnić wymaganie przed nim stawiane – uruchamianie się na różnych systemach operacyjnych (Windows, Linux, Mac) i w różnych przeglądarkach (IE, Firefox, Safari) – został zbudowany niejako obok .NET Framework. Fundamentem .NET Framework jest CLR. Silverlight został wyposażony w specjalne środowisko uruchomieniowe oraz w specjalny zbiór klas, aby móc spełnić tym wymaganiom. Jeśli chodzi o warstwę komunikacyjną to posiada on wbudowany WCF (Windows Communication Foundation). Chcąc skomunikować ze sobą Dynamics CRM oraz Silverlight będziemy łączyć ze sobą technologią ASP.NET oraz WCF. Jak dalej zostanie opisane – nie zawsze jest to, aż takie proste :)

Pierwszym krokiem jest skorzystanie z opcji dodania referencji do usługi. W przypadku starszych technologii w VS posiadaliśmy opcję Add Web Reference. Wraz z WCF dostaliśmy opcję Add Service Reference, którą można było zamienić na zwykłą Web Reference (wchodzą w dodatkowe ustawienia). W Silverlight nie mamy takiej opcji i musimy korzystać tylko z Service Reference – tak jak to jest pokazane na rysunku:

 

Skorzystanie z opcji dodania referencji do usługi spowoduje wyświetlenie okienka, w którym wprowadzić będzie trzeba adres, pod którym dostępna będzie usługa (np. http://localhost/MSCrmServices/2007/CrmService.asmx). Można tutaj również wskazać np. ścieżkę na lokalnym dysku gdzie znajduje się plik z definicją usługi (*.wsdl). Po odpowiednim skonfigurowaniu i wygenerowaniu namiastki zostanie w projekcie utworzony katalog Service References gdzie znajdziemy kod źródłowy stworzonej namiastki.

 

Oprócz kodu namiastki zostanie wygenerowany plik konfiguracyjny, który będziemy mogli wykorzystać w czasie tworzenia instancji namiastki. Zamiast pisać kod i wskazywać, z których wiązań i w jakiej konfiguracji należy korzystać można te wartości wskazać w pliku konfiguracyjnym i w czasie tworzenia instancji namiastki na ten plik się powoływać. Przykładowy plik konfiguracyjny wygląda następująco:

<configuration>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="CrmServiceSoap" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
                    <security mode="None" />
                </binding>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="
http://localhost/MSCrmServices/2007/CrmService.asmx"
                binding="basicHttpBinding" bindingConfiguration="CrmServiceSoap"
                contract="CrmSdk.CrmServiceSoap" name="CrmServiceSoap" />
        </client>
    </system.serviceModel>
</configuration>

Warto tutaj zwrócić uwagę na nazwę końcówki (endpoint), która w pokazanym pliku jest ustawiona na CrmServiceSoap. W momencie tworzenia instancji namiastki będzie można wskazać na jaką konfigurację WCF musi się powołać, aby poprawnie namiastkę zainicjować.

Warto tutaj zwrócić uwagę na nazewnictwo klas wygenerowanym z pliku *.wsdl usługi CRM. W czasie tworzenia namiastki poprzez zwykłe Web Reference dostawaliśmy w efekcie klasę CrmService. Tutaj otrzymujemy CrmServiceSoapClient. Inne klasy takie jak account, contact, reprezentujące obiekty CRM generowane są bez żadnych zmian.

Tworzenie instancji namiastki jest następujące:

CrmServiceSoapClient _client = new CrmServiceSoapClient("CrmServiceSoap");

gdzie CrmServiceSoapClient jest klasą wygenerowaną przez WCF, natomiast argumentem konstruktora tej klasy jest wskazanie konfiguracji końcówki z pliku konfiguracyjnego również wygenerowanego przez WCF.

Silverlight umożliwia wywoływanie tylko i wyłącznie metod asynchronicznych. Zatem w namiastce nie mamy metod CrmService takich jak Execute, Create, Update. Mamy natomiast metody ExecuteAsync, CreateAsync, itd. Wszelkie operacji przy pomocy Silverlight wykonywane są asynchronicznie !!! Mając to na uwadze po utworzeniu namiastki trzeba obsłużyć zdarzenia zakończenia wykonywania operacji asynchronicznej. Przykładowy kod wygląda tak:

_client.RetrieveMultipleCompleted += new EventHandler<RetrieveMultipleCompletedEventArgs>(OnClientRetrievedMultiple);
_client.ExecuteCompleted += new EventHandler<ExecuteCompletedEventArgs>(OnClientExecuteCompleted);

, gdzie metody OnClientRetrievedMultiple oraz OnClientExecuteCompleted są zdefiniowane następująco:

void OnClientExecuteCompleted(object sender, ExecuteCompletedEventArgs e) {}

void OnClientRetrievedMultiple(object sender, RetrieveMultipleCompletedEventArgs e) {}

Aby wiedzieć do jakiej organizacji się połączyć do tej pory (tzn. korzystając z Web Reference) otrzymywaliśmy klasę CrmAuthenticationToken, który umożliwiał wskazanie do której organizacji chcemy się połączyć, w jaki sposób chcemy dokonać uwierzytelnienia, itd. W przypadku WCF oczywiście otrzymujemy klasę CrmAuthenticationToken w namiastce jednakże klasa CrmServiceSoapClient nie posiada właściwości, która umożliwia ustawienia i wykorzystanie tokenu. Aby poprawnie połączyć się z usługą CRM musimy mieć możliwość dołączenia do żądań SOAP nagłówka – musimy mieć metodę GenerateAuthenticationHeader, którą mamy jak piszemy skrypt uruchamiany, np. na zdarzeniu OnLoad formatki CRM. Metodę tą możemy zbudować korzystając z kanały komunikacyjnego, z którego korzysta WCF. Musimy ręcznie dołączyć nagłówek do wiadomości wychodzących od naszego komponentu:

MessageHeader header = MessageHeader.CreateHeader("CrmAuthenticationToken",
                  "http://schemas.microsoft.com/crm/2007/WebServices",
                  "",
                  new CrmAuthenticationTokenSerializer(0, orgname, null));

OperationContext.Current = new OperationContext((IContextChannel)_client.InnerChannel);
OperationContext.Current.OutgoingMessageHeaders.Add(header);

Klasa CrmAuthenticationTokenSerializer jest naszą własną klasą dziedziczącą po XmlObjectSerializer:

    public class CrmAuthenticationTokenSerializer : XmlObjectSerializer
    {
        int _authType;
        string _organizationName;
        string _callerId;

        public CrmAuthenticationTokenSerializer (int authType, string organizationName, string callerId)
        {
            _authType = authType;
            _organizationName = organizationName;
            _callerId = callerId;
            if (_callerId == null)
            {
                _callerId = "00000000-0000-0000-0000-000000000000";
            }
        }


        public override void WriteStartObject(XmlDictionaryWriter writer, Object graph)
        {
        }

        public override void WriteObjectContent(XmlDictionaryWriter writer, Object graph)
        {
            string authToken = string.Format("<AuthenticationType xmlns='http://schemas.microsoft.com/crm/2007/CoreTypes'>

            {0}</AuthenticationType><OrganizationName xmlns='http://schemas.microsoft.com/crm/2007/CoreTypes'>

            {1}</OrganizationName><CallerId xmlns='http://schemas.microsoft.com/crm/2007/CoreTypes'>

            {2}</CallerId>", _authType, _organizationName, _callerId);

            writer.WriteRaw(authToken);
        }

        public override void WriteEndObject(XmlDictionaryWriter writer)
        {
        }


        public override bool IsStartObject(XmlDictionaryReader reader)
        {
            return true;
        }

        public override Object ReadObject(XmlDictionaryReader reader, bool verifyObjectName)
        {
            return null; 
        }

    }

Mając tak zdefiniowaną klasę możemy przystąpić do wywoływania metod usługi CRM. Jednakże w czasie wywołania najprostszego żądania, np. WhoAmIRequest dostaniemy błąd związany z komunikacją pomiędzy domenami. Dlaczego tak się dzieje ? O tym w kolejnym wpisie. Tam również kilka informacji na temat błędów związanych z metodami Retrieve oraz RetrieveMultiple.

SilverCRM cz. 1 – nowy projekt

Planując napisanie kilku wpisów poświęconych tworzeniu połączenie CRM z Silverlight jeden wpis chciałem poświęcić narzędziom, które trzeba mieć, aby móc sprostać temu zadaniu. Wtedy na rynku w wersji finalnej był VS 2008 a na portalu www.silverlight.net znaleźć można było szereg toolkitów, które dodawały do tego narzędzi chociażby nowy typ projektu.

W międzyczasie pojawił się produkt VS2010, który wszystkie narzędzia ma w sobie wbudowane więc z wpisu z przygotowania do rozpoczęcia pracy można było zrezygnować. Dla osób, które nie decydują się jeszcze na przejście na VS 2010 polecam lekturę portalu www.silverlight.net – tam są wszelkiego rodzaju informacje jakie narzędzia i jak skonfigurowane są potrzebne aby wykonać to co dalej w tym wpisie (i we wpisach kolejnych będzie opisane).

A więc do dzieła. Korzystam z Visual Studio Web Developer 2010 Express, które bez żadnych kosztów pobrać można ze strony: http://www.microsoft.com/express/

VS 2010

Tworząc nowy projekt wybieram szablon Silverlight –> Silverlight Application (ja preferuję C#). Po ustawieniu nazwy aplikacji, lokalizacji jej plików źródłowych oraz nazwy rozwiązania VS klikamy przycisk OK. Pojawi nam się okienko, przy pomocy którego będziemy mogli wygenerować aplikację internetową, w której będzie masz komponent Silverlight uruchamiany.

imageZ aplikacji takiej można oczywiście zrezygnować, jednakże w naszym przypadku chcemy, aby komponent Silverlight był uruchamiany w kontekście CRM. Zanim jednak ten komponent będziemy wbudowywać w CRM warto popracować nad samym komponentem: zbudować kod, przetestować, popracować nad wyglądem. Temu służy właśnie ta generowana aplikacja.

Na samym dole okienka mamy możliwość wybrania wersji Silverlight, z której będziemy korzystać. Domyślnie VS 2010 zainstalowany jest z wersją 3 Silverlight. Aby móc korzystać z wersji 4 należy doinstalować narzędzie, które jest do pobrania ze strony: http://www.microsoft.com/downloads/details.aspx?FamilyID=bf5ab940-c011-4bd1-ad98-da671e491009&displaylang=en (pamiętać należy, że jest to wersja RC2 – taka przynajmniej była aktualna w czasie pisania tego wpisu). Ja pozostanę na razie przy wersji 3, gdyż to co chcę zaprezentować nie wymaga wersji 4.

Po wybraniu OK czekamy chwilę na zakończenie procesu generowania projektów.

W oknie Solution Explorer zobaczymy dwa projekty – jeden odpowiada komponentowi Silverlight, drugi natomiast odpowiada aplikacji internetowej, która posłuży nam do testowania komponentu. Co wchodzi w skład poszczególnych projektów:

Solution Explorer

  1. Test1
    Jest to projekt naszego komponentu Silverlight. Predefiniowane mamy tutaj dwa pliki *.xaml wraz z plikami codebehind.
  2. Test1.Web
    Projekt ten ma za zadanie uruchomić nasz komponent. W ramach tego projektu znajduje się katalog ClientBin, do którego będzie kopiowany plik wyjściowy projekt Test1 po jego kompilacji (z rozszerzeniem *.xap). Plik ten będzie następnie uruchamiany w kontekście jeden ze stron Test1TestPage.*. Domyślnie mamy tutaj do dyspozycji strony *.html oraz *.aspx.

 

 

 

 

Po zbudowaniu (kombinacja Ctrl + F5) zostanie nam zaprezentowana strona *.aspx z tego projektu, gdyż właśnie ten projekt ustawiony jest domyślnie jako projekt startowy. Gdybyśmy zdecydowali się na stworzenie rozwiązania składającego się tylko z projektu Silverlight w efekcie otrzymalibyśmy plik *.xap, który następnie musimy sami wbudować w stronę internetową.

Kolejnym krokiem będzie nawiązanie połączenie z Dynamics CRM …

Przykład rozwiązania xRM – U.S. Air Force

Aby pokazać kolejny przykład przemawiający za rozwiązaniami opartymi o platformę Microsoft Dynamics CRM zapraszam do obejrzenia rozwiązania jakie zostało zbudowane u dość ciekawego klienta :) – w siłach powietrznych armii amerykańskiej.

http://www.microsoft.com/showcase/en/us/player/embed/0b7c863a-242b-4b90-b31d-988fd1318bb4

Konferencja “xRM jako nowy wymiar CRM”

Jako osoba, która jest częścią firmy Netwise muszę napisać o bezpłatnej konferencji, którą wraz z firmą Microsoft organizujemy. Odbędzie się ona we wtorek, 20.04.2010 w siedzibie Microsoft przy Al. Jerozolimskich 195A w Warszawie.

Agenda spotkania jest następująca:

    10:00

    kawa powitalna & rejestracja uczestników

    10:30

    powitanie

    10:35 – 11:30

    Koncepcja xRM a CRM

    11:30 – 11:45

    przerwa kawowa

    11:45 – 12:15

    Tworzenie aplikacji na platformie xRM

    12:15 – 13:00

    przerwa kawowa

    13:00 – 14:00

    Przykład wykorzystania platformy xRM w wybranych firmach – integracja z aplikacjami firm trzecich m.in. IFS, SAP.

    14:00 – 14:15

    przerwa kawowa

    14:15 – 15:00

    xRM w infrastrukturze własnej czy w hosting?

    15:00 – 15:15

    sesja Q&A

    15:15

    Zakończenie

Szczegóły związane z rejestracją na konferencję znaleźć można na stronie: http://konferencja.crmdynamics.pl/

.NET Framework 4.0 i Visual Studio 2010

Nadeszła wiekopomna chwila i oczom wszystkim na całym świecie ukazana została finalna wersja .NET Framework w wersji 4 oraz Visual Studio 2010.

Co nowego niesie ze sobą ta odsłona można przeczytać na blogu Scotta: http://weblogs.asp.net/scottgu/archive/2010/04/12/visual-studio-2010-and-net-4-released.aspx

Co ważne z punktu widzenia CRM ? A to, że CRM 5 jak zostanie zaprezentowany światu w wersji finalnej ma być zbudowany w oparciu właśnie o .NET Framework 4.0. Szczęściarzom, którzy uczestniczą we wczesnej adopcji CRM 5 pozazdrościmy bo z tego co można znaleźć na forach jest na co czekać.

Dynamics CRM + Silverlight

Dla osób, które chociaż troszeczkę śledzą to co dzieje się w Microsoft zapewne słyszały o technologii Silverlight – co to jest, do czego służy (w końcu jest czwarta wersje jest dostępna ;).

Jednym z moich celów, które przed sobą stawiam na najbliższy czas jest poznanie samej technologii, ale mając na uwadze możliwości integracji z Dynamics CRM bo to jest mój produkt flagowy. Pracuję właśnie nad bardziej rozbudowanym postem, który będzie opisywał moje początki w tematyce integracji tych dwóch technologii – wczoraj mówiłem o tej tematyce na spotkaniu grupy xRM’owej działającej przy polskim oddziale Microsoft. Przy okazji odbywało się tam również spotkanie poświęcone tylko i wyłącznie technologii Silverlight – może zacznę odwiedzać te spotkania regularnie – do czego zachęcam wszystkich entuzjastów technologii z Redmond.

xRM – pierwszy wpis na blogu

Pierwszy wpis, będący wstępem do tego, co bym chciał tutaj zamieścić. Zawodowo zajmuję się wdrażaniem systemów CRM a w szczególności systemu Microsoft Dynamics CRM. System ten jest idealnym przykładem koncepcji xRM czyli platformy, na bazie której jesteśmy w stanie zbudować dowolne rozwiązanie, które nie tylko będzie zarządzać relacjami z klientem, ale np. relacjami uczelni ze studentami, relacjami władz miasta z mieszkańcami.

Wyjaśnieniem tej koncepcji niech będzie ten krótki filmik :)

Ja ze swojej strony postaram się tutaj regularnie zamieszczać informacje związane nie tylko z biznesowym podejściem do tematu, ale również informacje związane z podejściem technicznym – będą tutaj wpisy o tym jak coś zrobić, jak coś zaimplementować, itd. :)