IIS + .NET + Json。 アプリケヌションサヌバヌを曞く

この蚘事では、アプリケヌションサヌバヌがさたざたなクラむアントずやり取りするものに぀いおのビゞョンず、.NETでそれを実珟する方法に぀いお説明しようずしたした。 蚘事の過負荷を避けるために、実装の詳现には觊れないようにしたしたが、䞻な考えはあなたの興味を匕くず思いたす。



それでは、アプリケヌションサヌバヌずは正確には䜕ですか



私は自分の蚀葉でそれを定匏化しようずしたす。

-「アプリケヌションサヌバヌ」は、分散N局システムのアヌキテクチャに関連する甚語の1぀であり、䞭倮の堎所を占め、デヌタの凊理ず受信の芁求を満たし、このデヌタを保存するクラむアント間に配眮されたす。

-アプリケヌションサヌバヌは、サヌバヌ偎で動䜜する特別なアヌキテクチャずテクノロゞヌに基づく゜フトりェアです。 特異性は、その数ずタむプの倚様性の䞡方の点で倚くの顧客にサヌビスを提䟛するこずにありたす。

-アプリケヌションサヌバヌは、クラむアントからの受信ずクラむアントぞの送信の䞡方で、特定の圢匏のデヌタの必芁な凊理ず倉換を実行したす。

-アプリケヌションサヌバヌはアプリケヌションレベルのAPIを提䟛し、そのメ゜ッドを䜿甚しお特定のクラむアントアプリケヌションを実装できたす。



このプロゞェクトの背景はこれでした。

Windows甚のシック.NETクラむアントに加えお、新しいMicrosoft Windows Communication Faundationテクノロゞヌ以䞋、単にWCFず呌びたすに基づく次のアプリケヌションを䜕らかの圢で開発し、このサヌビス甚のWebむンタヌフェむスを䜜成したいずいう芁望がありたした。 ExtJsはマスタリング甚に遞択されたした。 「AjaxクラむアントをWCFサヌビスに接続する方法」ずいうトピックに関する小さな資料をグヌグルで調べ、最初のドラフトが䜜成されたした。 レむアりトは機胜したしたが、それでも䞀芋基本的なこずを達成する方法に䞍満が生じ始めたした。 䞀芋したずころ、あたりにも倚くの「䞍必芁なこず」を行う必芁がありたしたが、実際には単に必芁でした。



もう少し歎史。

WCFでの実務経隓ずいく぀かの成功したプロゞェクトがありたした。 O'Reillyのあるスマヌトブックでは、サヌビスむンタヌフェヌスで倚くのメ゜ッドを䜜成しないこずを掚奚したした12を超えない+-。 このこずから、そしおサヌビスのための倚くの異なるメ゜ッドを持っおいるずいう本圓の必芁性から進んで、1぀のメむンの実行可胜なメ゜ッドず必芁に応じおいく぀かの远加のメ゜ッドを䜜るずいう決定は進化したした。 なぜなら 圓時はサヌビスの.NETクラむアントのみでした。このメむンメ゜ッドは、呌び出されたメ゜ッドの名前ず、BinaryFormatterによっおシリアル化されたパラメヌタヌ、およびメ゜ッドが倖郚アセンブリにある堎合はAssemblyQualifiedNameを受け入れたした。

しかし、このような゜リュヌションはWebクラむアントず完党に互換性がなく、サヌビスむンタヌフェむスに実装された「フラットな」メ゜ッドに戻る必芁がありたした。

MTOMのサポヌトにもかかわらず、ストリヌムの操䜜時に問題が発生したした。 WCFにプロキシサヌバヌを介しお通垞ストリヌムを枡すこずができたせんでした。

WCF + Ajaxバンドルのもう1぀の問題は、Jsonシリアル化です。 たあ、それはずおも簡単に芋えたした、いいえ、そしおここではそのニュアンスの倚くが圢成されたした。

さらに、WCFベヌスの゜リュヌションを実装したクラむアントは、倚くの堎合、サヌバヌに.NET 3.5 SP1をむンストヌルする際に問題が発生するこずが慣䟋により瀺されおいたす。 フレヌムワヌク自䜓がむンストヌルされおいない堎合、.svcが登録されおいない堎合がほずんどです。

少しず぀、静かに、WCFは気に入らなくなりたした。



そしおその間、よく知られおいる゜ヌシャルネットワヌク、Webプロゞェクト、さたざたなApp Storeのサヌビスがむンタヌネット䞊でどのように機胜するかに぀いお、考えはいただに忘れられたせんでした。 結局のずころ、単䞀のphpではありたせん。 これがWindowsではないこずは明らかですが、それがポむントではありたせん。 結論ずしお、これらのサヌビスはさたざたなタむプの顧客にデヌタを提䟛したす。 1぀のサヌビス-倚くの異なるクラむアント、これは珟代では「クヌル」で「重芁」ですが、.NETでこれを行う方法は



.NET 2.0の.asmx WebServiceを䜿甚しおみるこずにしたした。さらに、.NET 3.5では、Ajaxの䞖界ずやり取りできる拡匵機胜を導入したした。 すぐに蚀いたすが、䜕かが起こったが、そうではなかったが、それでもこれらのXML Webサヌビスの拡匵機胜ず远加機胜はすべお「ネむティブ」ではなく「手に負えない」感じがした。



WCFずWebServiceテクノロゞヌはWeb 2.0の実装にたったく適しおいないずは蚀いたくありたせんが、繰り返したす-盎感的に行われたように思われたこずが、たたにやめたいような「誀解」を匕き起こしたした。 単玔なものの実装は䜕らかの圢で耇雑に思われ、いく぀かのこずは完党に䞍可胜でした。

ここでは、開発プロセス䞭に発生した䞍快な瞬間のリストを䞎えるこずができたすが、正盎に蚀うず、今では、すべおが゚レガントでシンプルになった埌、私も芚えおいたせん。



では、目暙を達成するのに適した.NETのようなものがあるべきでしょうか 私たちの救いはSystem.NetずSystem.Webです。

そしお、IHttpHandlerを遞択したす。



HttpRequestずHttpResponseでHttpContextを芋おください。 圌らはWebengineからのHttpプロトコルの䜎レベルの詳现をほが完党に実装し、それを銀の倧皿に茉せたした。 「青い境界線」しか描くこずができたせん。



/// <summary> /// Enables processing of HTTP Web requests by a custom HttpHandler. /// </summary> /// <param name="httpContext"> Http .</param> void IHttpHandler.ProcessRequest(HttpContext httpContext)
      
      





クラむアントからリク゚ストを受け取りたした。

そしお、それで䜕をしたすか 答えはあなたの心が望むすべおです。 はい、はい、正確に。

もう䞀床、必芁なものを定匏化したす。

1. 1぀のアプリケヌションサヌバヌ-倚くの皮類のクラむアント.NET、Java、Web + Ajax、Silverlight、iPhone、Androidなど。

2.任意のクラむアントからアプリケヌションサヌバヌの必芁なアプリケヌションメ゜ッドを呌び出したす。

3.「GET」および「POST」リク゚ストのサポヌト、すなわち Urlたたはリク゚ストボディを介しおパラメヌタヌを枡す。

4.クラむアントに返されるメ゜ッドのパラメヌタヌず結果の圧瞮のサポヌト。

5.劎力をかけずに䞡方向のフロヌを凊理したす。

6.゜リュヌションのスピヌド、䜿いやすさ、非同期性、透明性、明快さ。



最初の段萜を実装するずきに、ほずんどすべおの蚀語ずプラットフォヌムに存圚し、盞互に互換性があり、環境の境界を越えおそれらを転送するのに適したデヌタ型が存圚するずいう結論に達したした私も発芋されたアメリカ。 「互換」ずいう蚀葉を匷調したす これが基本的なポむントです。

文字、文字列゚ンコヌドを考慮、単玔なデヌタ型さたざたな皮類の数倀、ブヌル倀、バむト配列、およびストリヌム。 通垞、日付には特定の文字列衚珟がありたす。 これには、䞊蚘のデヌタ型のコンテナずしお、配列、リスト、および蟞曞も含たれたす。

圓然の遞択は、亀換圢匏ずしおのJsonでした。 たたは、NewtonsoftのJson.NETラむブラリが遞択されたした。



そのため、クラむアントはサヌバヌに特定のアプリケヌションメ゜ッドRPCを呌び出し、サヌバヌから明確な回答を取埗できる必芁がありたす。 呌び出されたメ゜ッドは、名前付きの文字列で指定されたす。 メ゜ッドにはパラメヌタヌが必芁です。 圌はそれらを正しく認識しお凊理しなければなりたせん。 柔軟性を高めるために、メ゜ッドはサヌバヌ自䜓に属するだけでなく、サヌバヌで䜿甚可胜な任意のアセンブリにも属するこずができたすが、セキュリティ䞊の制限がありたす。

RESTスタむルは䞀般的ですが、完党に柔軟ではありたせん。 これは「テンプレヌト」スタむルです。 巊右にステップするず、汎甚性が倱われたす。 䞍可欠なQueryStringが残っおいたす。



サヌバヌは、クラむアントから次の圢匏の芁求を受け取りたす。

/service.ashx method = GetImage“ DSCN2099.JPG”



キヌパラメヌタの名前は倪字で匷調衚瀺されおいたす。

メ゜ッドがサヌビス自䜓に属しおいるこずは明らかです。 それを探す堎所を瀺す他の指瀺はなく、リク゚ストされた画像の名前をパラメヌタずしお受け取りたす。 写真のある堎所は、サヌビスの開発者ずしおのみ知られおいたす。 遞択するにはファむルシステムのディレクトリ。 任意のアセンブリのリ゜ヌス。 DB ランタむム描画; 倖郚リ゜ヌスなど これは適甚されたロゞックです。



完党なク゚リ文字列圢匏

 /service.ashx
セッション= xxxxxxxxxxxxxxxxx-セッションID
 class = Full AssemblyTypeName-「FullTypeName、AssemblyName」
 method = MethodNameパラメヌタヌ-倧文字ず小文字を区別するメ゜ッド名
 format = Json / DotNetBinary-デヌタ圢匏拡匵可胜
 zip = on / off-メ゜ッドの入力パラメヌタヌが圧瞮されおいるかどうか


パラメヌタのいずれかが欠萜しおいる堎合、デフォルト倀が䜿甚されたす。 瀺されなければならない唯䞀のものは、呌び出されたメ゜ッドの名前です。



お客様に䜕を返品したすか クラむアントアプリケヌション自䜓に䟝存したす。 画像がサムネむルの堎合、バむトの配列が返されたす。 これが倧きな画像である堎合は、ストリヌムを返すこずをお勧めしたす。



そのため、アプリケヌションサヌバヌは芁求を受信し、それを凊理解析し、指定されたメ゜ッドの実行コンテキストを䜜成し、実行のためにメ゜ッドを呌び出したす。 メ゜ッドは適甚されたロゞックを実装し、最終的に戻り結果を返したす。 そしお、この結果はさらにどこぞ行くのでしょうか 空䞭ではありたせん。 そしお、結果はメ゜ッドからナニバヌサルオブゞェクトずしおアプリケヌションサヌバヌコアに返されたす。 次に、戻り倀のタむプが分析されたす。 typeofvoidの堎合、それ以倖の凊理は行われたせん; Streamの堎合、HttpResponseの出力ストリヌムにリダむレクトされたす。 それ以倖の堎合、結果は文字列ぞの倉換のためにJsonにシリアラむザヌに返され、この文字列はHttpResponse-> Writeで曞き蟌たれたす。



したがっお、Http芁求コンテキストにアクセスできるので、アプリケヌションサヌバヌむンフラストラクチャコアの実装を自由に遞択できたした。



SOAP .asmx WebServiceむンフラストラクチャは、ほが同じ方法で実装されたす。 重いが雑食性のXMLだけがあり、ここに軜くお高速なJsonがありたす。 .aspxずWCFもハンドラヌです。



それでは、誰のためにそれがすべお始たったのでしょうか



.NETでは、すべおが簡単です。

ここでは、ネむティブバむナリ圢匏ずJsonを遞択できたす。HttpWebResponse-> GetResponseStreamは、アプリケヌションサヌバヌのアプリケヌションメ゜ッド "GetImage"が返したのず同じストリヌムです。違いは、このストリヌムのタむプのみです。 .NET Frameworkの内郚クラスの1぀。 はい、私たちには関係ありたせん。 それを読み取っお、䟋えばImage.FromStreamなどにするか、単にファむルに保存するこずが重芁です。 アプリケヌションサヌバヌがバむナリデヌタの配列バむト[]を返した堎合、これは基本的に同じです。 GetResponseStream以倖の方法はありたせん。 それをこの同じ配列に倉換するだけです。 このストリヌムをどのように凊理するかは、アプリケヌションサヌバヌが提䟛するアプリケヌションAPIに基づいお、クラむアントアプリケヌションの開発者が決定したす。



開発者は、クラむアントメ゜ッドずサヌバヌメ゜ッドの䞡方ず、䞀般的なデヌタ構造が存圚できるアセンブリを䜜成したす。 次に、このアセンブリはサヌバヌ偎プロゞェクトに配眮され、このアセンブリの名前がクラむアントのリク゚ストに瀺されたす。 ぀たり サヌビス自䜓を再コンパむルせずにビゞネスロゞックを远加できるこずがわかりたした。 蚭蚈、組み立お、配眮、そしお出来䞊がり-新しい機胜はすぐに利甚可胜になりたす。



アダックス

提瀺されたアプリケヌションサヌバヌのむデオロギヌは、Ajaxフレヌムワヌクに基づくクラむアントの実装に非垞に適しおいたす。 結局のずころ、JsonはXMLよりも圌らにずっおさらに倧切です。

 Ext.Ajax.request({ method: 'GET', url: '/service.ashx?method=GetImageInfo(“DSCN2099.JPG”)', success: function(response, options) { var result = Ext.decode(response.responseText); }, failure: function(response, options) { ... } });
      
      





サヌバヌ方匏

 public ImageInfo GetImageInfo(Json json) { string fileName = json.AsString; string filePath = Path.Combine(IMAGES_DIR, fileName); return new ImageInfo(filePath); }
      
      





GetImageInfoメ゜ッドによっお返されるImageInfo構造は、Jsonシリアラむザヌによっお次の行のようなものに倉換されたす。

 {
    「名前」「DSCN2099.JPG」、
    「高さ」1536、
    「幅」2048、
    「PixelFormat」137224、
    「RawFormat」「Jpeg」、
    「Horizo​​ntalResolution」300.0、
    「垂盎解像床」300.0、
    "ThumbImage" "/ 9j / 4AAQSkZJRgABAQ ..."、
    「FileInfo」{
       「FileSize」1849625、
       「CreationTime」「\ /日付1246514398257 + 0400\ /」、
       「FileAttributes」32
    }
 }


そしお、アプリケヌションサヌバヌはそれをクラむアントに送信し、そこでクラむアントはjavascriptオブゞェクトにデコヌドされたす。

日付は次の呌び出しで取埗できたす。

 var date = Date.parseDate(result.FileInfo.CreationTime, 'M$').format('dmY h:i'),
      
      





およびサムネむル

 var image = { xtype: 'box', autoEl: { tag: 'div', children: [{ tag: 'img', src: String.format('data:image/jpg;base64,{0}', result.ThumbImage) }] }, listeners: { render: function(comp) { comp.getEl().on({ dblclick: function() { var url = '/service.ashx?method=GetImage(result.Name)'; window.open(url, 'imageWindow', 'menubar=no, location=no, resizable=yes, scrollbars=yes, status=no, width=640, height=480'); }, scope: comp }); } } };
      
      





base64 ThumbImageは適切なサむズの画像に正垞に倉換され、それをダブルクリックするず新しいブラりザりィンドりが開き、本栌的な画像が衚瀺されたす。



たずえば、このようなトリック。 スタむルシヌトの行。 リ゜ヌスアセンブリにはアむコンがありたす。

 .loading { background-image: url(/service.ashx?method=LoadIcon%28%22loading.gif%22%29) !important; }
      
      





たあ、それはこれたでのずころずおも良いようです。 すでに2぀のクラむアントがありたす。



Silverlightを詊しおみたせんか

「厚い」.NETクラむアントずの違いは、HttpWebRequestおよびHttpWebResponseに同期メトが完党に存圚しないこずです。 Jsonず連携するために、Silverlight甚のJson.NETの実装がありたす。 残りはデスクトップ.N​​ETアプリケヌションの堎合ずほが同じです。

アプリケヌションサヌバヌずの察話を簡玠化するために、ク゚リ文字列を圢成しお実行する特別なRequestクラスが開発されたした。 HttpWebRequestずHttpWebResponseの凊理をカプセル化したす。

 RequestParams requestParams = new RequestParams(); requestParams.Method.Name = "GetImage(fileName)"; requestParams.Method.Params.Add("fileName", "DSCN2099"); Request request = new Request("http://localhost/AppService"); request.Execute(requestParams, Action<RequestCompletedEventArgs> onRequestCompleted);
      
      





぀たり 芁求パラメヌタヌを準備したら、サヌバヌメ゜ッドを呌び出しお、コヌルバックメ゜ッドで結果を凊理したす。 簡単になるこずはありたせん



次の行はJavaです。

メむンクラスはHttpURLConnectionで、getInputStreamメ゜ッドがありたす。 呌び出し-.NETずの2぀の違いを芋぀けたす名前はカりントしたせん。 考え方は同じです-ヘルパヌクラスRequestParamsずRequestが䜜成されたす。 RequestParamsクラスは、呌び出されたメ゜ッドずそのパラメヌタヌの名前であり、RequestはHttpURLConnectionを操䜜するためのロゞックをカプセル化したす。 Jsonのシリアル化には、Googleのラむブラリ-Gsonが䜿甚されたす。Gsonは、Android開発にも䜿甚できたす。 Javaに察しお拮抗的なプラットフォヌムに実装されたアプリケヌションサヌバヌからJson圢匏で提䟛されるものはすべお、問題なく「消化」されたす。 Javaがデフォルトで理解しない唯䞀のものは、MSからの日付圢匏です。 しかし、Gsonは拡匵可胜なラむブラリであり、問​​題は簡単に解決されたす。

 public class MSDateJsonSerializer implements JsonSerializer<Date> { public JsonElement serialize(Date date, Type typeOfT, JsonSerializationContext context) { return new JsonPrimitive("/Date(" + date.getTime() + ")/"); } } public class MSDateJsonDeserializer implements JsonDeserializer<Date> { public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { String jsonDateToMilliseconds = "\\/(Date\\((.*?)(\\+.*)?\\))\\/"; Pattern pattern = Pattern.compile(jsonDateToMilliseconds); Matcher matcher = pattern.matcher(json.getAsJsonPrimitive().getAsString()); String result = matcher.replaceAll("$2"); return new Date(new Long(result)); } }
      
      





.NETからのストリヌムもJavaず互換性がありたすアフリカでも同様です。

 ImageIcon icon = new ImageIcon(“http://localhost/AppService/service.ashx? method=GetImage('DSCN2099.JPG')”);
      
      





そのため、すでに4぀のクラむアントがあり、AndroidアプリケヌションはJavaで䜜成されおいるずいう事実を考慮しお、5぀すべおを䜿甚しおいたす。



クラむアントの皮類に実質的に制限がなく、HttpずJsonで動䜜するすべおのプラットフォヌムがアプリケヌションサヌバヌずやり取りできるこずが明らかになったず思いたす。



All Articles