\


 Tuesday, 28 March 2006
Další FAQ k .NET Remotingu
  1. Při použití CAO (Client Activated) objektu nebo při vrácení MarshalByRefObjectu ze SAO (Server Activated) objektu fungují volání metod jen v lokální síti. Na počítači přistupujícím přes internet (a komunikujícím tedy většinou přes adresu firewallu/routeru) volání metody vzdáleného CAO objektu vždy selže.

    Důvodem je, že každý CAO objekt je identifikován unikátním dynamickým URI, které je vygenerováno na serveru. Server za firewallem/routerem ale vrátí název počítače nebo IP adresu (v závislosti na nastavení vlastnosti useIpAddress u přenosového kanálu), které jsou platné pouze v lokální síti. Nastavením vlastnosti machineName u kanálu můžeme zadat, jaký název serveru (IP adresa) mají být v URI pro CAO objekty vráceny - zadáme tedy externí a pro klienty viditelnou adresu (např. adresu firewallu).

    V Konfiguračním souboru

    <channel ref="tcp" machineName="serverExternalVisibleName">
    </channel>

    V kódu:
    IDictionary properties = new Hashtable();
    properties["machineName"] = "serverExternalVisibleName";
    TcpChannel tcpChannel = new TcpChannel(properties, null, null);
    ChannelServices.RegisterChannel(tcpChannel);
  2. Při komunikaci se serverovým objektem dostanete hlášení, že selhalo přihlášení k proxy (The remote server returned an error: (407) Proxy Authentication Required).

    Net Remoting podporuje přihlášení k webovému serveru, ale jeho autoři trestuhodně a pravděpodobně omylem (ale i ve verzi 2.0?) nezveřejnili pro zadání přihlašovacích údajů objekt IWebProxy. Jediným nepříliš čistým řešením (pomineme-li nespolehlivé zadání autentizačních údajů přes třídu GlobalProxySelection) je použití reflection a nastavení privátního člena _proxyObject v objektu HttpClientChannel.

    //Vytvoření nového http komunikačního kanálu
    HttpChannel channel = new HttpChannel();
    
    //Získáme deskriptor člena _clientChannel (klientský http kanál) ve třídě HttpChannel
    FieldInfo clientChannelFO = typeof(HttpChannel).GetField("_clientChannel",   BindingFlags.Instance|BindingFlags.NonPublic);
    
    //Získání instance HttpClientChannel
    HttpClientChannel clientChannel = clientChannelFO.GetValue(channel);
    
    //Získání deskriptoru proxy objektu
    FieldInfo proxyObject = typeof(HttpClientChannel).GetField("_proxyObject", BindingFlags.Instance | BindingFlags.NonPublic);
    
    //Vytvoření nového proxy objektu
    IWebProxy authProxy = new WebProxy("proxy", 80); 
    
    //Pro autentizaci k proxy použijeme údaje přihlášeného uživatele
    authProxy.UseDefaultCredentials = true;
    
    //Nastavení nové proxy v objektu HttpClientChannel
    proxyObject.SetValue( clientChannel, proxy );
    

Starší FAQ k .NET Remotingu na tomto blogu

Dva nejčastější dotazy k .NET Remotingu
Dotazy a odpovědi k .NET Remotingu



Monday, 27 March 2006 23:47:11 (Central Europe Standard Time, UTC+01:00)       
Comments [0]  .NET Framework | .Net Remoting


 Sunday, 17 October 2004
Dotazy a odpovědi k .NET Remotingu

Tento spot přímo navazuje na starší spot o nejčastějších problémech v .NET Remotingu.

Dotazy v konferencích se často týkají událostí. Důvodem je hlavně to, že mnoho knih (namátkou třeba Building XML Web Services for Microsoft .Net platform) obsahuje “postup” pro rozchození události, který nefunguje. V čem je problém?

Když ve vzdáleném serverovém objektu nadeklarujete událost a pokusíte se k ní zaregistrovat delegáta ukazujícího na metodu na klientovi, dostanete při běhu aplikace výjimku, že se nepodařilo nahrát assembly s typem, ve kterém se nachází klientská obslužná metoda události. Server odmítne registraci delegáta u události, protože nedokáže ověřit signaturu metodu, na níž odkazuje delegát - server nemůže nalézt assembly s typem, ve kterém je deklarována metoda, protože assembly je známa a rozmístěna jen na klientovi.

Správný postup při deklaraci a používání událostí v .NET Remotingu

  1. Vytvořte jednu assembly se serverovým objektem a nadeklarujte serverové události. Assembly umístěte pouze na serveru.
  2. Vytvořte assembly, v níž bude sdílená třída s obslužnou metodou serverové události a dále bude třída obsahovat událost vlastní, která bude stejného typu jako serverová. V těle obslužné metody serverové události pouze vyvolejte událost vlastní - lokální a přepošlete argumenty obdržené ze serveru. Assembly umístěte na server i na klienta, protože klient si zaregistruje obslužnou metodu sdíleného typu k serverové události (v té chvíli již server dokáže ověřit signaturu metodu a nahrát typ, ve kterém je metoda deklarována) a současně si klient přihlásí odběr lokální události ze sdíleného typu a takto zprostředkovaně zpracuje událost ze serveru.
  3. Vytvořte klientskou assembly. Assembly umístěte pouze na klienta.

Dalším problémem u vzdálených událostí je korektní ošetření stavu, kdy se klient odpojí a na serveru zůstane zaregistrován delegát (například spadne spojení). Aby nedošlo k výjimce na serveru při pokusu distribuovat událost, tak jako nejjednodušší cesta se nabízí dekorování obslužné metody na klientovi atributem OneWay - atribut způsobí, že server ignoruje všechny návratové hodnoty a výjimky z metody. Velkou nevýhodou je ale hromadění delegátů ukazujících do "prázdna" a tím zvýšená režie na distribuci každé události. Lepším řešením je ruční vyvolání každého delegáta registrovaného k události a po odchycení výjimky vyřazení delegáta z další distribuce událostí.

public void OnServerEvent(EventArgs e)
{
    Delegate[] delegatesList = ServerEvent.GetInvocationList();
    foreach(ServerEventHandler clientDelegate in delegatesList)
    {
        try
        {
            clientDelegate(e);
        }
        catch
        {
            ServerEvent -= clientDelegate;
        }
    }
}



Sunday, 17 October 2004 17:33:00 (Central Europe Standard Time, UTC+01:00)       
Comments [8]  .Net Remoting


 Friday, 14 May 2004
Kniha Network programming for the Microsoft .Net Framework

Kniha Network programming for the Microsoft .Net Framework je úvodem do síťového programování. Slovo úvodem bych zdůraznil, protože žádné rozsáhlé případové studie v ní nenaleznete.
Po obligátním a  povrchním úvodu do .Net Frameworku, nás autoři seznámí se “streamy” a pochopitelně se soustředí na třídu NetworkStream. Následuje popis práce s thready a ukázky asynchronního návrhového vzoru (metody Begin*, End*)- i když je problematice věnováno plných 19 stran, nečekejte žádné "best practices", ale spíše upovídaný přepis toho, co je v MSDN. Ukázek asynchronního návrhového vzoru je v celé knize hříšně opulentní množství , takže tato kapitola je jen "lákavou" návnadou.
Dále je v knize vysvětlen význam serializace a probrány jsou XML, binární a SOAP serializace. Když už je serializace probírána do takových detailů, jakými jsou XML atributy, mohla být zmíněna i dynamická redefinice atributů za asistence třídy XmlAttributeOverrides.
Lehký úvod do jmenného prostoru System.Net, jehož smysl mi v kompozici knihy uniká, je vystřídán popisem protokolů IPV4 a IPV6 a metod třídy DNS. Tato kapitola mi připadá z celé knihy nejpovedenější, protože z ní čiší, že její autor své téma podrobně zná, ale přitom dokáže na vyhrazeném prostoru vybrat to podstatné a nezabíhat do zdržujících detailů.
Následující dvě kapitoly tvoří jádro knihy, protože se zabývají klientskými a serverovými sokety a také jejich nadstavbami s jednodušším API (TcpClient, TcpListener). Bohužel tyto kapitoly trpí také největší nevyvážeností ve zpracování tématu. Přístup autorů kolísá od pasivního přejímání informací z MSDN k neustálému zdůrazňování, že pro většinu synchronních metod existují jejich asynchronní doplňky. Když jsem se tuto zajímavou informaci dověděl potřetí a prohlédl si další úmorný Step By Step příklad určený pravděpodobně programátorům po akutní lobotomii provedené brokovnicí, měl jsem chuť připojit se dobře cíleným výstřelem k zástupu šťastných idiotů, abych dokázal kapitoly dočíst. Tam, kde by měla být tématika zpracována velmi prodrobně i s ukázkami, se autoři omezí na shrnující tabulky, jejichž pravděpodobně jediným smyslem je rychlé navýšení počtu popsaných normostran. Moje výtka směřuje hlavně k zcela nedostatečné dokumentaci enumerace SocketOption.
Kromě TCP/IP protokolu jsou zde i ukázky UDP protokolu a implementace takzvaných "Raw" soketů. "Raw" sokety jsou vysvětleny na příkladu ICMP protokolu (což není nic jiného než všem důvěrně známý PING). Slušelo by se zmínit, že na Windows 2000 a XP mohou "Raw" sokety otevřít pouze administrátoři. (ping.exe může spustit každý uživatel, jde asi o jedinou výjimku).
Důležitost tříd WebClient, WebResponse a WebRequest je vyzdvižena v kapitole nazvané "Using the Network". Tato kapitola je povedená, i když zde asi nenaleznete nic překvapivého. Zmíněny jsou cookies, různé způsoby autentizace, certifikáty, SSL.
Z dalších kapitol rychle získáte pocit, že se autoři zavázali dodat dílko o vyšším počtu stran, a proto zařadili témata jako jsou Web Services a .Net Remoting. Sice jsou vždy naťuknuty pokročilé vlastnosti (SOAP extenze, Channel sinks), ale z jejich odfláknutého vysvětlení si začátečník bude brzy zoufat a slabší nátura se k těmto konceptům kvůli neumětelství autorů již nikdy nevrátí. Jako leitmotiv knihy:) se zde objevuje podrobné vysvětlení asynchronního volání WWW služeb.
Autoři se také s těžko pochopitelnou vervou pustí i do vysvětlování Code Acces Security. Jejich snaha se ale omezí na výčet oprávnění a hrubý přehled významu konstitutivních složek CAS, takže kdybych se s CAS setkal poprvé, získám mylný dojem, že CAS je nesmysl bez jakékoli užitné hodnoty. Jsme také poučeni, že bychom měli komunikaci mezi sokety kryptovat, protože svět plný hackerů čeká na naše pakety. Děkuji za osvětu, hned se cítím jako up-to-date vývojář, teď si najdu jen ve slovníku cizích slov význam termínu kryptovat, abych ty hackery svými programy sejmul. :)
Doporučení pro psaní výkonných aplikací jsou shrnuta v mozaice nazvané "Network performance and scalability. Zajímavá je hlavně část týkající se doporučení pro používání "Nagle" algoritmu, ale ani ostatní rady vašim aplikacím neublíží.
Zcela do počtu je kratičká poslední kapitola Advancements in .Net Framework programming, jejíž originální teze by se dala shrnout "Nebojte se, v příští verzi bude zase vše lepší, výkonnější a bezpečnější".
Co říci závěrem? Jestliže se sokety začínáte a jste úplní zelenáči, kniha se Vam bude hodit, i když si z ní odnesete hlavně poznatek, že sokety jsou tady proto, aby bylo na čem demonstrovat dokonalý asynchronní návrhový vzor. :) Jste-li pokročilý vývojář a v knize hledáte neotřelé rady starých zkušených harcovníků, schovejte peněženku, zamáčkněte slzu kanoucí za odpíraným poznáním a vyberte si jiný titul.
Anotace
Název: Network Programming For the Microsoft .Net Framework
Autoři: Jones, A; Ohlund, J; Olson, L;
Nakladatelství: Microsoft Press 2004



Friday, 14 May 2004 20:05:00 (Central Europe Standard Time, UTC+01:00)       
Comments [0]  .NET Framework | .Net Remoting | ASP.NET | Web Services


 Sunday, 02 May 2004
Dva nejčastější dotazy k .NET Remotingu

V diskuzních fórech se objevuje mnoho dotazů k .NET Remotingu, ale následující dva jsou evergreenem. Těm z Vás, kdo záludnosti .Net Remotingu ještě neodhalili sami, nabízím řešení a doufám, že dotazů ve fórech ubude.:)

V .Net Frameworku 1.1 dojde při pokusu o komunikaci se vzdáleným objektem k výjimce SecurityException nebo SerializationException. V .Net Frameworku 1.0 aplikace funguje bez problémů.

.Net Framework 1.1  z bezpečnostních důvodů nepovoluje ve výchozí konfiguraci deserializaci všech typů, takže k výjimce dojde například při předání  potomka třídy MarshalByRefObject z klienta na server  nebo při registraci delegáta k události. Řešením je nastavit u objektu formatter, který provádí (de)serializaci, že povolujeme deserializaci všech typů. Úroveň deserializace vyjadřuje enumerace TypeFilterLevel a chování shodného s verzí 1.0 dosáhneme použitím hodnoty Full. Hodnotu Full přiřadíme objektu formatter (přesněji poskytovateli objektu formatter) v konfiguračním souboru nebo přímo v kódu. Nastavení úrovně full musí být provedeno na serveru a když  používáte zpětná volání (callback) nebo události, tak musíte úroveň Full nastavit i na klientovi. Nezapomeňte, že byste měli zprávy mezi klientem a serverem přenášet přes https nebo je alespoň kryptovat.

Nastavení v  konfiguračním souboru


Server

<configuration>

  <system.runtime.remoting>

    <application>

      <channels>

         <channel ref="http" port="7777">

      <serverProviders>

     <provider ref="wsdl" />

      <formatter ref="soap" typeFilterLevel="Full" />

      <formatter ref="binary" typeFilterLevel="Full" />

     </serverProviders>

   </channel>

</channels>

</application>

</system.runtime.remoting>

</configuration>

Klient

<configuration>

  <system.runtime.remoting>

    <application>

    <channels>

      <channel ref="http" port="0">

        <clientProviders>

        <formatter ref="binary" />

      </clientProviders>

      <serverProviders> 

         <formatter ref="binary" typeFilterLevel="Full" />

     </serverProviders>

  </channel>

  </channels>

 </application>

</system.runtime.remoting>

</configuration>


Nastavení v kódu


BinaryServerFormatterSinkProvider binProvider = new BinaryFormatterSinkProvider();
binProvider.TypeFilterLevel = TypeFilterLevel.Full;

SoapServerFormatterSinkProvider soapProvider = new SoapServerFormatterSinkProvider();
soapProvider.TypeFilterLevel = TypeFilterLevel.Full;


Za další otázkou se skrývá záludnější problém. Při použití http kanálu, binárního formatteru (formátovač mi nějak do pera nejde) a hostování vzdáleného objektu v IIS dostanete na klientovi občas následující výjimku.

An unhandled exception of type 'System.Runtime.Serialization. SerializationException' occurred in mscorlib.dll
Additional information: BinaryFormatter Version incompatibility. Expected Version 1.0. Received Version <nesmyslné číslo>

 

Matoucí je hlavně nesmyslné číslo na konci, které zcela evidentně nepředstavuje žádnou známou verzi formatteru a tedy nelze jednoduše nalézt pravou příčinu nepovedené deserializace. Vysvětlení je prosté - došlo k chybě na úrovni IIS a klientovi se vrátí chybové http hlášení (například HTTP/1.1 500 Internal server error), protože WWW server/vzdálený objekt není z nějakého důvodu dostupný. Bohužel formatter se snaží nalézt v této zprávě hlavičku s verzí formatteru použitého na serveru a protože ji nalézt nemůže, vyhodí matoucí hlášku, že našel nesmyslnou verzi, jejíž číslo vezme bůhvíkde.

Pastí je v .Net Remotingu více, klidně mi napište, s jakými problémy jste se setkali vy, a já připravím pokračování poradny:)



Sunday, 02 May 2004 18:08:00 (Central Europe Standard Time, UTC+01:00)       
Comments [0]  .Net Remoting