ASMX Webサービス開発テクニック

この記事では、ASMXテクノロジーを使用してSOAP Webサービスを開発するためのさまざまな手法と、このテクノロジー全般について説明します。 SOAPに加えて、AJAXの実装も検討されます。 この記事は、既にこの記事に精通している人にも、最初のWebサービスを作成しようとしている人にも役立ちます。





内容



歴史的背景

ASMXおよびWCF

はじめに

  1. シンプルな構造
  2. 推奨設計
  3. wsdl.exeを使用したプロキシクラス
  4. このwsdlのサーバークラス
  5. アヤックス
  6. メタデータをリクエストする
  7. ファイルアクセス
  8. web.config
  9. 複数のasmxファイル
  10. ウェブページの置換
  11. 拡張機能の交換
  12. wsdlを非表示にする
  13. 例外
  14. soap:ヘッダー
  15. キャッシング
  16. ソープエクステンション
  17. Visual StudioでのX64デバッグ
  18. デプロイ(公開)
  19. IISアプリケーションプール
  20. 開発ツール




歴史的背景



当初から、MicrosoftはSOAP標準の主要な開発者の1人でした。 2002年、ASP.NET 1.0の最初のバージョンの一部として、彼女はASMX(Active Server Method Extended)テクノロジを導入しました。これにより、最新のVisual Studio 2002の開発者は、SOAP Webサービスを簡単に作成および利用できます。 MSDNで公式に公開されているこのテクノロジの名前は「XML Webサービス」です。 当時、SOAPはWeb開発の世界で最初の重大な一歩を踏み出していました。 W3Cコンソーシアム 、2000年にSOAP 1.1、2003年にSOAP 1.2(2007年に更新)を承認しました。 したがって、テクノロジーを習得しやすくし、新しい標準に適用することが非常に重要でした。 そして、この目標は達成されました-Webサービスを操作するために、開発者はXML、SOAP、およびWSDLを知る必要さえありませんでした。



その後、ASMXテクノロジーは広く普及し、認知されるようになりました。 また、Microsoftは最初からWebサービス拡張(WSE)アドオンを提供しており、WS-Security、WS-Policy、WS-ReliableMessagingなどのさまざまなWS- *セキュリティ仕様を実装できました。 最新バージョン-WSE 3.0は2005年にリリースされました。 そして2007年、.NET 3.0の一部として、Windows Communication Foundation(WCF)テクノロジーが導入され、ASMXの公式の代替となりました。 ASMXテクノロジーは長い間開発されていないという事実にもかかわらず、広く使用され続けており、最新バージョンの.NET Frameworkでサポートされています。



ASMXおよびWCF



Googleが見ている両方のタイプのWebサービスの数を比較するのは興味深いです: 314,000 ASMX6,280 WCF

なぜASMXテクノロジーは今でも人気があるのですか? すべてが非常に簡単です。ほとんどの場合、使いやすく、問題を完全に解決します。 WCFの利点は、たとえば、高速トランスポート、二重化、ストリーミング、最新のセキュリティ標準への準拠、RESTが必要な場合に現れます。 ところで、RESTのみが必要な場合は、WCFの代わりにASP.NET Web APIテクノロジーを使用する価値があります。



各テクノロジーの利点を具体的にリストします。

ASMXの長所:

  • 開発のしやすさ
  • 習得が簡単
  • 設定の「地獄」はありません


WCFの長所:

  • 非常に多様で柔軟な輸送手段
  • 実際の進化するテクノロジー
  • さまざまなホスティングオプション
  • さまざまなWS- *標準を実装する機能


したがって、WCFはデータ転送の分野では「スイスナイフ」であり、ASMXは「ソリッドドライバー」です。 そして何よりも、もちろん、両方のツールを使用できます。 インターネットでWCFを開発する方法については、より詳しく説明しているため、古いWebサービスをサポートする必要がある人や、この技術を使用して新しいサービスを作成する人に役立つASMXに関する記事を書く必要があると判断しました。











はじめに



この記事では、このテクノロジーを使用してWebサービスを開発する際に適用できる20の異なる実用的な方法について説明します。 例のシナリオは次のとおりです。 定期的に更新される財務諸表のデータベースがあります。 さまざまな顧客がこれらのレポートに関連するデータを常に持つことができる汎用メカニズムを開発する必要があります。 解決策:2つの方法でSOAP Webサービスを作成します。



  • 最初のメソッドは一定期間を取り、この期間に出現したすべてのレポートの識別子を返します
  • 2番目のメソッドはレポート識別子を受け取り、レポートデータ自体を返します


Webサービスのコンシューマーは、最後の要求の瞬間からの期間を示す要求を最初のメソッドに定期的に送信し、応答に識別子がある場合、2番目のメソッドを介してデータを要求します。



推奨設計のコードに基づいて例が示されており、それらをテストするには、プロキシクラスの例に示すように、GetReportInfo Webメソッドを呼び出すだけです。



1.最も単純な設計



最も単純なWebサービス設計の説明から始めましょう。 注意、例は純粋に理論的です! 彼は労働者ですが、実際にこれを行うことはありません。 これは、ASMXテクノロジー自体のシンプルさの単なるデモンストレーションです。



Visual Studioで、 「ASP.NET Empty Web Application」または「ASP.NET Web Service Application」というFinReportWebServiceという新しいプロジェクトを作成します。 2つのファイルFinReport.asmxおよびFinReportService.csを追加し、FinReport.asmxをWebサービスではなくテキストファイルとして追加して、単一のファイルにします。



FinReport.asmx

<% @ Class = "FinReportWebService.FinReportService" %>



FinReportService.cs

システムを使用して ;

System.Web.Services を使用します。



名前空間 FinReportWebService {



パブリック クラス FinReportService {

[ WebMethod ]

public int [] GetReportIdArray( DateTime dateBegin、 DateTime dateEnd){

int [] array = new int [] {357、358、360、361};

配列を返します。

}



[ WebMethod ]

public FinReport GetReport( int reportID){

FinReport finReport = new FinReport (){

ReportID = reportID、

日付= 新しい DateTime2015、03、15 )、

情報= 「一部の情報」

};



return finReport;

}

}



パブリック クラス FinReport {

public int ReportID { get ; セット ; }

public DateTime Date { get ; セット ; }

パブリック ストリング Info { get ; セット ; }

}

}



F5 キーを押してWebサーバーを起動し、ブラウザーでFinReport.asmxを開きます。







できた 次に、順番に分析します。 Webサービスは、1つの必須機能を備えた1つの通常のクラスで表されます-そのメソッドの一部は、特別な属性[WebMethod]でマークされます。 このようなクラスメソッドは、適切な呼び出しシグネチャを持つWebサービスWebメソッドになります。 このクラスにはデフォルトのコンストラクターが必要です。 IISは新しい要求ごとに、デフォルトのコンストラクターでインスタンス化し、適切なメソッドを呼び出します。



最小構成の2番目に必要な部分は、拡張子がasmxのファイルで、その中にこのクラスを指定する必要があります。



この手動で作成されたasmxファイルとVisual Studioが作成するasmxファイルを比較するのは興味深いことです。 為替レートを返す別のWebサービスを作成するとします。 [ 新しい項目追加 ]メニューを使用して、WebサービスタイプのExchangeRate.asmxファイルを追加します。







F7を1回または2回押すと、以下が表示されます。

<% @ WebService Language = "C#" CodeBehind = "ExchangeRate.asmx.cs"    クラス = "FinReportWebService.ExchangeRate" %>



Language = "C#"演算子は初歩的なものであり、asmxファイル内にソースコードを直接記述する場合にのみ必要です。 このようなコードは動的にコンパイルされます。 しかし、一般的には、Webサービスの動的コンパイルは良い習慣ではないと思います。特に、特別なApp_Codeフォルダーの使用はお勧めしません。 CodeBehind = "ExchangeRate.asmx.cs"ステートメントは、Visual Studioレベルで2つのファイルを単にリンクします。



2.推奨設計



この例では、同じWebサービスがより適切な方法で実装されています。 これはより正確なコードですが、デモンストレーションとしてのみ機能します。 たとえば、承認、例外処理、ロギングなどの重要な標準事項はここにはありません。 また、この例は、この記事の他の手法を実証する基礎となります。 FinReportService.csファイルで、コンテンツを次のソースコードに置き換えます。



FinReportService.cs

システムを使用して ;

System.Web.Services を使用します。

System.Xml.Serialization を使用します。



名前空間 FinReportWebService {



[ WebServiceBinding (ConformsTo = WsiProfiles .BasicProfile1_1)]

[ WebService (説明= " Fin。Reports " 、名前空間= XmlNS)]

パブリック クラス FinReportServiceWebService {

public const string XmlNS = "http://asmx.habrahabr.ru/" ;



[ WebMethod (説明= 「期間ごとのレポートIDのリストの取得」 )]

public GetReportIdArrayResult GetReportIdArray( GetReportIdArrayArg arg){

新しい GetReportIdArrayResult ()を返す {

ReportIdArray = new int [] {357、358、360、361}

};

}



[ WebMethod (説明= " 取得   報告する   ID " )]で

public GetReportResult GetReport( GetReportArg arg){

新しい GetReportResult ()を返す {

レポート= 新しい FinReport {

ReportID = arg.ReportID、

日付= 新しい DateTime2015、03、15 )、

情報= getReportInfo(arg.ReportID)

}

};

}



プライベート 文字列 getReportInfo( int reportID){

return "ReportID =" + reportID;

}

}





// [シリアル化可能]

// [XmlType(Namespace = FinReportService.XmlNS)]

パブリック クラス FinReport {

public int ReportID { get ; セット ; }

public DateTime Date { get ; セット ; }

パブリック ストリング Info { get ; セット ; }

}



パブリック クラス GetReportIdArrayArg {

public DateTime DateBegin { get ; セット ; }

パブリック DateTime DateEnd { get ; セット ; }

}



パブリック クラス GetReportIdArrayResult {

public int [] ReportIdArray { get ; セット ; }

}



パブリック クラス GetReportArg {

public int ReportID { get ; セット ; }

}



パブリック クラス GetReportResult {

公開 FinReportレポート{ get ; セット ; }

}

}



変更を分析しましょう。

属性[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]は、WebサービスがWSI Basic Profile 1.1仕様に準拠しているかどうかを確認することを意味します。 たとえば、操作の名前のオーバーロード、または[SoapRpcMethod]属性の使用を禁止します。 このような違反は、Webサービスエラー「The service」FinReportWebService.FinReportServiceが「Simple SOAP Binding Profile Version 1.0仕様を満たしていません」につながります。 この属性が存在しない場合、違反は「このWebサービスはWS-I Basic Profile v1.1の要件を満たしていません」という警告のみにつながります。 通常、相互運用性を高めるために、この属性を追加することをお勧めします。



[WebService(Description =“ Fin。Reports”、Namespace = XmlNS)]属性には3つのプロパティのみがあります

名前空間-デフォルトのCML名前空間-必須

説明-ブラウザーに表示されるWebサービスの説明

名前-Webサービスの名前(クラス名はデフォルトで取得されます)



WebServiceクラスから継承すると、HttpContext、HttpSessionState、およびその他のオブジェクトへのアクセスが提供されます。これらのオブジェクトは、場合によっては役立ちます。



属性[WebMethod(Description = "IDによるレポートの取得")]では 、原則として、ブラウザーでWebメソッドを説明するDescriptionのみが指定され、他のプロパティはほとんど使用されません。



着信パラメーターと戻り値特別なクラスにカプセル化することを個人的にお勧めします。 たとえば、メソッドの名前に接尾辞-Argおよび-Resultを追加して、引数と結果を意味します。 この例では、簡単にするために、それらはすべて同じファイルFinReportService.csにありますが、実際のプロジェクトでは、それぞれをFinReportServiceTypesなどの特別なフォルダーの個別のファイルに配置します。 共通のクラスから継承することも便利です。



理論上、属性[Serializable]および[XmlType(Namespace = FinReportService.XmlNS)]は、Webメソッドのすべてのネイティブクラスに対して指定する必要があります。 ただし、この場合は必要ありません。 実際、XMLシリアル化のみが実行される場合、[Serializable]属性は不要であり、XML名前空間はデフォルトで[WebService]属性から取得されます。 WCFとは異なり、ASMXは通常のXmlSerializerを使用します。これにより、[XmlType]、[XmlElement]、[XmlIgnore]などの標準属性を使用してシリアル化を広く制御できます。



3. wsdl.exeを使用したプロキシクラス



wsdl.exeユーティリティは、asmxのSOAP Webサービスを利用するための適切な手法です。 wsdlファイルまたはリンクを使用して、プロキシクラス(このWebサービスへのアクセスを可能な限り単純化する特別なクラス)を生成します。 もちろん、Webサービスがどのテクノロジーに実装されているかは問題ではなく、ASMX、WCF、JAX-WS、NuSOAPなど、どのようなものでもかまいません。 ところで、WCFにはSvcUtil.exeと呼ばれる同様のユーティリティがあります。



このユーティリティはC:\ Program Files(x86)\ Microsoft SDKs \ Windowsフォルダーにあります。さらに、.netバージョン、ビット深度、Windowsバージョン、Visual Studioに応じて異なるバージョンで表示されます。







使用例

wsdl http://192.168.1.101:8080/SomeDir/SomeService?wsdl

wsdl HabraService.wsdl



FinReportWebServiceのクライアントを作成しましょう。 現在のソリューションまたは新しいソリューションで、新しいWindows FormsプロジェクトFinReportWebServiceClientを作成します。 その中にProxyClassフォルダーを追加し、wsdl.exeユーティリティをその中にコピーして、その中にGenProxyClass.batバッチファイルを作成します。

wsdl /n:FinReportWebServiceClient.ProxyClass http:// localhost:3500 / FinReport.asmx?wsdl

一時停止



引数/n:FinReportWebServiceClient.ProxyClassを使用して、クラスの名前空間を指定します。 実行すると、FinReportService.csファイルが取得されます。 ソリューションエクスプローラー-すべてのファイルを表示を使用して、3つのファイルすべてをソリューションに含めます。







フォームにボタンを追加すると、次の3つのメソッドがフォームのソースコードに含まれます。

public static FinReportService GetFinReportService(){

var service = new FinReportService ();

service.Url = "http:// localhost:3500 / FinReport.asmx" ;

service.Timeout = 100 * 1000;

返品サービス;

}





private void webMethodTest_GetReportIdArray(){

var service = GetFinReportService();

var arg = new GetReportIdArrayArg ();

arg.DateBegin = new DateTime (2015、03、01);

arg.DateEnd = new DateTime (2015、03、02);



var result = service.GetReportIdArray(arg);

MessageBox .Show( "result.ReportIdArray.Length =" + result.ReportIdArray.Length);

}





private void webMethodTest_GetReport(){

var service = GetFinReportService();

var arg = new GetReportArg ();

arg.ReportID = 45;



var result = service.GetReport(arg);

MessageBox .Show(result.Report.Info);

}



プロキシクラスの最も重要なプロパティはUrlとタイムアウトであり、タイムアウトはミリ秒単位で示され、100秒がデフォルト値です。 これを使用して、Webサービスの動作をテストできます。 GetReportメソッドを呼び出し、result.Report.Infoフィールドに入力することにより、さらなるテクニックの作業のデモが表示されます。



外部xsdスキームを参照するwsdlファイルを使用してプロキシクラスを作成する場合、これらすべてのスキームをコマンドにリストする必要があります。

wsdl / n:MyNamespace HabraService.wsdl Data.xsd Common.xsd Schema.xsd



ただし、プロキシクラスを手動で作成することに加えて、Visual Studioでは自動的に作成できます。 「サービス参照の追加」項目を使用すると、WCFテクノロジを使用してプロキシクラスを作成できます。また、Advancedには、ASMXテクノロジを使用して作成する「Web参照の追加」ボタンがあります。



4.このwsdlのサーバークラス



ご存じのように、ASMXテクノロジーのWebサービスのwsdl記述は自動的に生成されます。 ただし、特定のwsdlファイルに対応するWebサービスを開発するという逆の問題が発生する場合があります。 同じwsdl.exeユーティリティを使用して解決されます。 クラスから必要なスケルトンを作成でき、Webメソッドのプログラムロジックを実装するだけです。



たとえば、Webサービスのwsdlを取得します。 ブラウザからファイルFinReport.wsdlとして保存するか、ここからコピーします。

FinReport.wsdl
<? xml   バージョン = " 1.0 "   エンコーディング = " utf-8 " ?>

< wsdl:定義   xmlns:tm = " http://microsoft.com/wsdl/mime/textMatching/ "   xmlns:soapenc = " http://schemas.xmlsoap.org/soap/encoding/ "   xmlns:mime = " http://schemas.xmlsoap.org/wsdl/mime/ "   xmlns:tns = " http://asmx.habrahabr.ru/ "   xmlns:soap = " http://schemas.xmlsoap.org/wsdl/soap/ "   xmlns:s = " http://www.w3.org/2001/XMLSchema "   xmlns:soap12 = " http://schemas.xmlsoap.org/wsdl/soap12/ "   xmlns:http = " http://schemas.xmlsoap.org/wsdl/http/ "   targetNamespace = " http://asmx.habrahabr.ru/ "   xmlns:wsdl = " http://schemas.xmlsoap.org/wsdl/ " >

< wsdl:ドキュメント   xmlns:wsdl = " http://schemas.xmlsoap.org/wsdl/ " > Fin。 レポート</ wsdl:ドキュメンテーション >

< wsdl: タイプ >

< s:スキーマ   elementFormDefault = " qualified "   targetNamespace = " http://asmx.habrahabr.ru/ " >

< s:要素   name = " GetReportIdArray " >

< s: complexType >

< s: シーケンス >

< s:要素   minOccurs = " 0 "   maxOccurs = " 1 "   name = " arg "   type = " tns:GetReportIdArrayArg " />

</ s:シーケンス >

</ s:complexType >

</ s:要素 >

< s:complexType   name = " GetReportIdArrayArg " >

< s: シーケンス >

< s:要素   minOccurs = " 1 "   maxOccurs = " 1 "   name = " DateBegin "   タイプ = " s:dateTime " />

< s:要素   minOccurs = " 1 "   maxOccurs = " 1 "   name = " DateEnd "   タイプ = " s:dateTime " />

</ s:シーケンス >

</ s:complexType >

< s:要素   name = " GetReportIdArrayResponse " >

< s: complexType >

< s: シーケンス >

< s:要素   minOccurs = " 0 "   maxOccurs = " 1 "   name = " GetReportIdArrayResult "   type = " tns:GetReportIdArrayResult " />

</ s:シーケンス >

</ s:complexType >

</ s:要素 >

< s:complexType   name = " GetReportIdArrayResult " >

< s: シーケンス >

< s:要素   minOccurs = " 0 "   maxOccurs = " 1 "   name = " ReportIdArray "   タイプ = " tns:ArrayOfInt " />

</ s:シーケンス >

</ s:complexType >

< s:complexType   name = " ArrayOfInt " >

< s: シーケンス >

< s:要素   minOccurs = " 0 "   maxOccurs = " 無制限 "   name = " int "   タイプ = " s:int " />

</ s:シーケンス >

</ s:complexType >

< s:要素   name = " GetReport " >

< s: complexType >

< s: シーケンス >

< s:要素   minOccurs = " 0 "   maxOccurs = " 1 "   name = " arg "   type = " tns:GetReportArg " />

</ s:シーケンス >

</ s:complexType >

</ s:要素 >

< s:complexType   name = " GetReportArg " >

< s: シーケンス >

< s:要素   minOccurs = " 1 "   maxOccurs = " 1 "   name = " ReportID "   タイプ = " s:int " />

</ s:シーケンス >

</ s:complexType >

< s:要素   name = " GetReportResponse " >

< s: complexType >

< s: シーケンス >

< s:要素   minOccurs = " 0 "   maxOccurs = " 1 "   name = " GetReportResult "   type = " tns:GetReportResult " />

</ s:シーケンス >

</ s:complexType >

</ s:要素 >

< s:complexType   name = " GetReportResult " >

< s: シーケンス >

< s:要素   minOccurs = " 0 "   maxOccurs = " 1 "   名前 =レポート  タイプ = " tns:FinReport " />

</ s:シーケンス >

</ s:complexType >

< s:complexType   name = " FinReport " >

< s: シーケンス >

< s:要素   minOccurs = " 1 "   maxOccurs = " 1 "   name = " ReportID "   タイプ = " s:int " />

< s:要素   minOccurs = " 1 "   maxOccurs = " 1 "   name = " Date "   タイプ = " s:dateTime " />

< s:要素   minOccurs = " 0 "   maxOccurs = " 1 "   名前 =情報  タイプ = " s:string " />

</ s:シーケンス >

</ s:complexType >

</ s:スキーマ >

</ wsdl:タイプ >

< wsdl:メッセージ   name = " GetReportIdArraySoapIn " >

< wsdl:パート   name = " parameters "   element = " tns:GetReportIdArray " />

</ wsdl:メッセージ >

< wsdl:メッセージ   name = " GetReportIdArraySoapOut " >

< wsdl:パート   name = " parameters "   element = " tns:GetReportIdArrayResponse " />

</ wsdl:メッセージ >

< wsdl:メッセージ   name = " GetReportSoapIn " >

< wsdl:パート   name = " parameters "   element = " tns:GetReport " />

</ wsdl:メッセージ >

< wsdl:メッセージ   name = " GetReportSoapOut " >

< wsdl:パート   name = " parameters "   element = " tns:GetReportResponse " />

</ wsdl:メッセージ >

< wsdl:portType   name = " FinReportServiceSoap " >

< wsdl:操作   name = " GetReportIdArray " >

< wsdl:ドキュメント   xmlns:wsdl = " http://schemas.xmlsoap.org/wsdl/ " >期間のレポートIDのリストを取得</ wsdl:documentation >

< wsdl:入力   message = " tns:GetReportIdArraySoapIn " />

< wsdl:出力   message = " tns:GetReportIdArraySoapOut " />

</ wsdl:操作 >

< wsdl:操作   name = " GetReport " >

< wsdl:ドキュメント   xmlns:wsdl = " http://schemas.xmlsoap.org/wsdl/ " > IDによるレポートの取得</ wsdl:documentation >

< wsdl:入力   message = " tns:GetReportSoapIn " />

< wsdl:出力   message = " tns:GetReportSoapOut " />

</ wsdl:操作 >

</ wsdl:portType >

< wsdl:バインディング   name = " FinReportServiceSoap "   type = " tns:FinReportServiceSoap " >

< 石鹸:結合   transport = " http://schemas.xmlsoap.org/soap/http " />

< wsdl:操作   name = " GetReportIdArray " >

< soap:操作   soapAction = " http://asmx.habrahabr.ru/GetReportIdArray "   style = " document " />

< wsdl: 入力 >

< 石鹸:ボディ   use = " literal " />

</ wsdl:入力 >

< wsdl: 出力 >

< 石鹸:ボディ   use = " literal " />

</ wsdl:出力 >

</ wsdl:操作 >

< wsdl:操作   name = " GetReport " >

< soap:操作   soapAction = " http://asmx.habrahabr.ru/GetReport "   style = " document " />

< wsdl: 入力 >

< 石鹸:ボディ   use = " literal " />

</ wsdl:入力 >

< wsdl: 出力 >

< 石鹸:ボディ   use = " literal " />

</ wsdl:出力 >

</ wsdl:操作 >

</ wsdl:バインディング >

< wsdl:バインディング   name = " FinReportServiceSoap12 "   type = " tns:FinReportServiceSoap " >

< soap12:バインディング   transport = " http://schemas.xmlsoap.org/soap/http " />

< wsdl:操作   name = " GetReportIdArray " >

< soap12:操作   soapAction = " http://asmx.habrahabr.ru/GetReportIdArray "   style = " document " />

< wsdl: 入力 >

< soap12:ボディ   use = " literal " />

</ wsdl:入力 >

< wsdl: 出力 >

< soap12:ボディ   use = " literal " />

</ wsdl:出力 >

</ wsdl:操作 >

< wsdl:操作   name = " GetReport " >

< soap12:操作   soapAction = " http://asmx.habrahabr.ru/GetReport "   style = " document " />

< wsdl: 入力 >

< soap12:ボディ   use = " literal " />

</ wsdl:入力 >

< wsdl: 出力 >

< soap12:ボディ   use = " literal " />

</ wsdl:出力 >

</ wsdl:操作 >

</ wsdl:バインディング >

< wsdl:サービス   name = " FinReportService " >

< wsdl:ドキュメント   xmlns:wsdl = " http://schemas.xmlsoap.org/wsdl/ " > Fin。 レポート</ wsdl:ドキュメンテーション >

< wsdl:ポート   name = " FinReportServiceSoap "   binding = " tns:FinReportServiceSoap " >

< soap:アドレス   location = " http:// localhost:3500 / FinReport.asmx " />

</ wsdl:port >

< wsdl:ポート   name = " FinReportServiceSoap12 "   binding = " tns:FinReportServiceSoap12 " >

< soap12:アドレス   location = " http:// localhost:3500 / FinReport.asmx " />

</ wsdl:port >

</ wsdl:サービス >

</ wsdl:定義 >



FinReportWebServiceByWsdlという名前で、ソリューションに新しい空のWebプロジェクトを作成します。 ServerClassフォルダーを追加し、そこにファイルFinReport.wsdlおよびwsdl.exeをコピーします。 その中にGenServerClass.batバッチファイルを作成します。

wsdl / server /n:FinReportWebServiceByWsdl.ServerClass FinReport.wsdl

一時停止



実行すると、FinReportService.csファイルが取得されます。 ソリューションに4つのファイルすべてを含めます。







したがって、ご覧のとおり、プロキシクラスを生成することとの唯一の違いはサーバー属性です。 これにより、抽象的に記述されたWebメソッドでWebServiceから継承された抽象クラスが作成されます。 継承できますが、すべての属性をコピーする必要があるため、次のように行うことを提案します。 クラス定義を新しいファイルと名前空間にコピーし、abstractという単語を削除して、メソッドの実装を記述します。 コードをフォーマットした後、次のファイルを取得しました

システムを使用して ;

System.Web.Services を使用します。

System.Web.Services.Description を使用します。

System.Web.Services.Protocols を使用します。

FinReportWebServiceByWsdl.ServerClass を使用します。



名前空間 FinReportWebServiceByWsdl {



[ WebService (Namespace = "http://asmx.habrahabr.ru/" )]

[ WebServiceBinding (Name = "FinReportServiceSoap" 、Namespace = "http://asmx.habrahabr.ru/" )]

パブリック クラス FinReportServiceWebService {



[ WebMethod ]

[ SoapDocumentMethod"http://asmx.habrahabr.ru/GetReportIdArray"

RequestNamespace = "http://asmx.habrahabr.ru/"

ResponseNamespace = "http://asmx.habrahabr.ru/"

Use = SoapBindingUse .Literal、

ParameterStyle = SoapParameterStyle .Wrapped)]



public GetReportIdArrayResult GetReportIdArray( GetReportIdArrayArg arg){

新しい GetReportIdArrayResult ()を返します。

}





[ WebMethod ]

[ SoapDocumentMethod"http://asmx.habrahabr.ru/GetReport"

RequestNamespace = "http://asmx.habrahabr.ru/"

ResponseNamespace = "http://asmx.habrahabr.ru/"

Use = SoapBindingUse .Literal、

ParameterStyle = SoapParameterStyle .Wrapped)]



public GetReportResult GetReport( GetReportArg arg){

新しい GetReportResult ()を返す {

レポート= 新しい FinReport {

ReportID = arg.ReportID、

日付= 新しい DateTime2015、03、15 )、

情報= 「ByWSDL」

}

};

}

}

}



このコードでは、ユーティリティは、デフォルトで暗黙的に決定されたWebサービスのパラメーターを属性を使用して明示的に説明しました。 この新しいクラスを指すファイルFinReportByWsdl.asmxを追加するだけです。

<% @ Class = "FinReportWebServiceByWsdl.FinReportService" %>





5. ajax



ASMX Webサービスは、JSON形式でデータを送受信できます。これにより、ajax技術を実装できます。 サンプルを機能させるには、Webプロジェクトに次の3つのファイルが必要です。



FinReport.asmx-最初の例と同じ、1行のみ

<% @ Class = "FinReportWebService.FinReportService" %>



FinReportService.cs-コードは次のものに変更されます

システムを使用して ;

using System.Text;

System.Web.Script.Serialization を使用します。

System.Web.Script.Services を使用します。

System.Web.Services を使用します。

Newtonsoft.Json を使用



名前空間 FinReportWebService {

[ ScriptService ]

[ WebServiceBinding (ConformsTo = WsiProfiles .BasicProfile1_1)]

[ WebService (Description = " Fin。Reports " 、Namespace = "http://asmx.habrahabr.ru/" )]

パブリック クラス FinReportServiceWebService {



[ ScriptMethod (ResponseFormat = ResponseFormat .Json)]

[ WebMethod ]

public GetReportResult Method_1_POST_Objects( GetReportArg arg){

return getFinReportResult(arg.ReportID、 "Method_1_POST_Objects" );

}





[ ScriptMethod (ResponseFormat = ResponseFormat .Json、UseHttpGet = true )]

[ WebMethod ]

public string Method_2_GET( int id){

var result = getFinReportResult(id、 "Method_2_GET" );

string text = JsonConvert .SerializeObject(result);

戻りテキスト。

}





[ ScriptMethod (ResponseFormat = ResponseFormat .Json)]

[ WebMethod ]

パブリック 文字列 Method_3_POST( int id){

var result = getFinReportResult(id、 "Method_3_POST" );

JavaScriptSerializer js = 新しい JavaScriptSerializer ();

return js.Serialize(結果);

}





[ ScriptMethod (ResponseFormat = ResponseFormat .Json)]

[ WebMethod ]

パブリック 文字列 Method_4_POST_ComplexArg( string json){

var arg = JsonConvert .DeserializeObject < GetReportArg >(json);

var result = getFinReportResult(arg.ReportID、arg.Token + " Received 。" );

return JsonConvert .SerializeObject(result);

}





[ ScriptMethod (ResponseFormat = ResponseFormat .Json)]

[ WebMethod ]

public DateTime Method_5_TransformDate( DateTime dateTime){

return dateTime.AddYears(-3).AddDays(-5).AddHours(-2).AddMinutes(6);

}





[ ScriptMethod (ResponseFormat = ResponseFormat .Json)]

[ WebMethod ]

public void Method_6_POST_NonStandard( int id){

var result = getFinReportResult(id、 "Method_6_POST_NonStandard、 My   テキスト " );

string text = JsonConvert .SerializeObject(result);

byte [] data = Encoding .UTF8.GetBytes(テキスト);



Context.Response.Clear();

Context.Response.ContentType = "application / json; charset = utf-8" ;

Context.Response.AddHeader( "content-length" 、data.Length.ToString());

Context.Response.BinaryWrite(データ);

Context.Response.Flush();

}





private GetReportResult getFinReportResult( int id、 string info){

新しい GetReportResult ()を返す {

レポート= 新しい FinReport (){

ReportID = id、

情報=情報、

日付= 新しい DateTime2015、03、15 )、

}

};

}

}





パブリック クラス FinReport {

public DateTime Date { get ; セット ; }

パブリック ストリング Info { get ; セット ; }

public int ReportID { get ; セット ; }

}



パブリック クラス GetReportArg {

public int ReportID { get ; セット ; }

パブリック ストリングトークン{ get ; セット ; }

}



パブリック クラス GetReportResult {

公開 FinReportレポート{ get ; セット ; }

}

}



Page.htm-実際のWebページ

<! doctype html >

< html >

< >



< メタ 文字セット = utf-8>

< script src = "// ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></ スクリプト >



< スクリプト >

$(ドキュメント).ready( function (){

$( "#btn1" ).click( function (){

var arg = {arg:{ReportID:1}};



$ .ajax({

タイプ: "POST"

contentType: "application / json; charset = utf-8"

url: "/FinReport.asmx/Method_1_POST_Objects"

データ:JSON.stringify(arg)、

dataType: "json"

成功: 関数 (データ、ステータス){

$( "#div1" ).html(data.d.Report.Info);

}、

エラー: 関数 (リクエスト、ステータス、エラー){アラート( "エラー" ); }

});

});



$( "#btn2" ).click( function (){

$ .ajax({

タイプ: "GET"

contentType: "application / json; charset = utf-8"

url: "/FinReport.asmx/Method_2_GET"

データ:{id:2}、

dataType: "json"

成功: 関数 (データ、ステータス){

$( "#div2" ).html(JSON.parse(data.d).Report.Info);

}、

エラー: 関数 (リクエスト、ステータス、エラー){アラート( "エラー" ); }

});

});



$( "#btn3" ).click( function (){

$ .ajax({

タイプ: "POST"

contentType: "application / json; charset = utf-8"

url: "/FinReport.asmx/Method_3_POST"

データ: '{"id":3}'

dataType: "json"

成功: 関数 (データ、ステータス){

$( "#div3" ).html(JSON.parse(data.d).Report.Info);

}、

エラー: 関数 (リクエスト、ステータス、エラー){アラート( "エラー" ); }

});

});





$( "#btn4" ).click( function (){

var arg = {ReportID:4、Token: " トークン   メソッド 4。 " };

var argObj = {json:JSON.stringify(arg)};



$ .ajax({

タイプ: "POST"

contentType: "application / json; charset = utf-8"

url: "/FinReport.asmx/Method_4_POST_ComplexArg"

データ:JSON.stringify(argObj)、

dataType: "json"

成功: 関数 (データ、ステータス){

$( "#div4" ).html(JSON.parse(data.d).Report.Info);

}、

エラー: 関数 (リクエスト、ステータス、エラー){アラート( "エラー" ); }

});

});



$( "#btn5" ).click( function (){

var now = new Date();

var arg = {dateTime:now};



$ .ajax({

タイプ: "POST"

contentType: "application / json; charset = utf-8"

url: "/FinReport.asmx/Method_5_TransformDate"

データ:JSON.stringify(arg)、

dataType: "json"

成功: 関数 (データ、ステータス){

var date = new Date(parseInt(data.d.replace( "/ Date(""" ).replace( ")/""" )、10));

$( "#div5" ).html(date.toString());

}、

エラー: 関数 (リクエスト、ステータス、エラー){アラート( "エラー" ); }

});

});



$( "#btn6" ).click( function (){

$ .ajax({

タイプ: "POST"

contentType: "application / json; charset = utf-8"

url: "/FinReport.asmx/Method_6_POST_NonStandard"

データ: '{"id":6}'

dataType: "json"

成功: 関数 (データ、ステータス){

$( "#div6" ).html(data.Report.Info);

}、

エラー: 関数 (リクエスト、ステータス、エラー){アラート( "エラー" ); }

});

});





});

</ スクリプト >



</ >

< 本体 >



< div id = "div1"> Div 1 </ div >

< div id = "div2"> Div 2 </ div >

< div id = "div3"> Div 3 </ div >

< div id = "div4"> Div 4 </ div >

< div id = "div5"> Div 5 </ div >

< div id = "div6"> Div 6 </ div >

<br />

< button id = "btn1">方法1 </ button >

<br />

< button id = "btn2">方法2 </ button >

<br />

< button id = "btn3">方法3 </ button >

<br />

< button id = "btn4">方法4 </ button >

<br />

< button id = "btn5">方法5 </ button >

<br />

< button id = "btn6">方法6 </ button >



</ body >

</ html >



この例では、 Newsonsoft.Jsonとも呼ばれるJson.NETライブラリも使用してます。



WebサービスがJSONで機能するには、2つの新しい属性を適用する必要があります。

[ScriptService] – , [ScriptMethod], ResponseFormat — JSON XML, UseHttpGet – – GET POST.



- 6 , ajax.



1 . 2 GetReportArg GetReportResult. :

{

" arg ": {

"ReportID": 1

}

}



{

" d ": {

"__type": "FinReportWebService.GetReportResult" ,

"Report": {

"ReportID": 1 ,

"Date": "/Date(1426356000000)/" ,

"Info": "Method_1_POST_Objects"

       }

}

}

, . JSON- - «d». "__type": «FinReportWebService.GetReportResult». "/Date(1426356000000)/" . , 5 , , , .



2 . . GET, , json-, . data: { id: 2 }, URL http://localhost:3500/FinReport.asmx/Method_2_GET?id=2, URL.





{

" d": "{\"Report\":{\"ReportID\":2,\"Date\":\"2015-03-15T00:00:00\",\"Info\":\"Method_2_GET\"}}"

}

, JSON.parse(data.d), :

{

" Report": {

"ReportID": 2 ,

"Date": "2015-03-15T00:00:00" ,

"Info": "Method_2_GET"

    }

}

, Json.NET . contentType: «application/json; charset=utf-8», , GET. CSRF. URL . GET .



3. , POST . :

{

" id ": 3

}

:

{

" d": "{\"Report\":{\"ReportID\":3,\"Date\":\"\\/Date(1426356000000)\\/\",\"Info\":\"Method_3_POST\"}}"

}



4. , var arg = { ReportID: 4, Token: " 4." }; :

{

"json": "{\"ReportID\":4,\"Token\":\"   4\"}"

}

.



5. , . 1 «Date»: "/Date(1426356000000)/". – , 1 1970 UTC (UNIX epoch). , Date new Date(milliseconds), :

var date = new Date(parseInt(data.d.replace( "/Date(" , "" ).replace( ")/" , "" ), 10));



- :

{

" dateTime": "2015-03-25T05:49:13.604Z"

}



6. , . , .

{

" Report": {

"Date": "2015-03-15T00:00:00" ,

"Info": "Method_6_GET_NonStandard,   " ,

       "ReportID": 6

}

}

, «d». GET. , - «application/json;».



maxJsonLength


maxJsonLength web.config:

<? xml   version = " 1.0 " ?>

< configuration >

  

< system.web >

< compilation   debug = " true "   targetFramework = " 4.0 " />

</ system.web >



< system.web.extensions >

< scripting >

< webServices >

< jsonSerialization   maxJsonLength = " 1073741824 " />

</ webServices >

</ scripting >

</ system.web.extensions >



</ configuration >





6.



, , IP- URL. , . , . DNS-, . getReportInfo()

private string getReportInfo() {

var request = this .Context.Request;

// var request = HttpContext.Current.Request;



StringBuilder sb = new StringBuilder ();

sb.Append( "IP = " ).AppendLine(request.UserHostAddress);

sb.Append( "URL = " ).AppendLine(request.Url.OriginalString);

sb.Append( "Header 'Connection' = " ).AppendLine(request.Headers[ "Connection" ]);



DateTime dnsDate = DateTime .Now;

TimeSpan dnsSpan;



try {

// throw new Exception("   .");

var entry = Dns.GetHostEntry(request.UserHostAddress);

dnsSpan = DateTime .Now.Subtract(dnsDate);

sb.Append( "HostName = " ).AppendLine(entry.HostName);



} catch ( Exception ex) {

dnsSpan = DateTime .Now.Subtract(dnsDate);

sb.AppendLine(ex.Message);

}



sb.Append( "dnsSpan = " ).AppendLine(dnsSpan.ToString());

return sb.ToString();

}





7.



, -. getReportInfo :

private string getReportInfo( int reportID) {

string dirRoot = HttpContext .Current.Server.MapPath( "~" );



StringBuilder sb = new StringBuilder ();

sb.AppendLine( "dirRoot = " + dirRoot);



string fileCars = HttpContext .Current.Server.MapPath( "~/bin/MyFiles/Cars.txt" );

sb.AppendLine( "fileCars = " + fileCars);



try {

sb.AppendLine( "Line 1 = " + File .ReadAllLines(fileCars)[0]);

File .AppendAllText(fileCars, Environment .NewLine + DateTime .Now + " ReportID = " + reportID);



} catch ( Exception ex) {

sb.AppendLine(ex.Message);

}



string dirFiles = Path .Combine(( new DirectoryInfo (dirRoot)).Parent.FullName, "FinReportWebService_Files" );

sb.AppendLine( "dirFiles = " + dirFiles);



try {

Directory .CreateDirectory(dirFiles);

string newFile = Path .Combine(dirFiles, Guid .NewGuid() + ".txt" );

File .WriteAllText(newFile, "ReportID = " + reportID);

sb.AppendLine(newFile);



} catch ( Exception ex) {

sb.AppendLine(ex.Message);

}





return sb.ToString();

}

MyFiles Cars.txt Build Action: None / Copy always - :







bin MyFiles , . FinReportWebService_Files, .



, getReportInfo , :



-

Cars.txt





FinReportWebService_Files







- IIS, :

dirRoot = C:\CommonFolder\publish_FinReport

fileCars = C:\CommonFolder\publish_FinReport\bin\MyFiles\Cars.txt

Line 1 = Audi

Access to the path 'C:\CommonFolder\publish_FinReport\bin\MyFiles\Cars.txt' is denied.

dirFiles = C:\CommonFolder\FinReportWebService_Files

Access to the path 'C:\CommonFolder\FinReportWebService_Files' is denied.

. 19. IIS.



8. web.config



web.config ASP.NET . ASP.NET , asmx -. . , , ASP.NET .



web.config


web.config :

<? xml   version = " 1.0 " ?>

< configuration >



< appSettings >

< add   key = " ReportType "   value = " 8 " />

< add   key = " ReportSubject "   value = "   " />

</ appSettings >



< system.web >

< compilation   debug = " true "   targetFramework = " 4.0 " />

   </ system.web >



</ configuration >

compilation.



, . , :

システムを使用して ;

using System.Collections.Generic;

System.Configuration を使用します。



namespace FinReportWebService {

internal static class WebConfig {



public static int ReportType { get { return getStructureValue< int >( "ReportType" ); } }

public static string ReportSubject { get { return getTextValue( "ReportSubject" ); } }

public static string DbLogin { get { return getTextValue( "DbLogin" , true ); } }

public static string DbPass { get { return getTextValue( "DbPass" , true ); } }



//==========================================================



private static string getTextValue( string name, bool getDefaultOnNotFound = false ) {

string value = ConfigurationManager .AppSettings[name];



if (value == null && !getDefaultOnNotFound) {

throw new KeyNotFoundException ( "   web.config     '" + name + "'" );

}



return value;

}





private static T getStructureValue<T>( string name, bool getDefaultOnNotFound = false ) where T : struct {

string textValue = getTextValue(name, getDefaultOnNotFound);



if (textValue == null ) {

return default (T);

}



try {

T value = (T) Convert .ChangeType(textValue, typeof (T));

return value;



} catch ( Exception ex) {

string message = " web.config '{0}' '{1}' '{2}'" ;

message = string .Format(message, name, textValue, typeof (T).Name);

throw new InvalidCastException (message, ex);

}

}



}

}



, FinReportService.cs getReportInfo :

private static string getReportInfo( int reportID){

StringBuilder sb = new StringBuilder ();

{

sb.Append( "ReportType =" ).AppendLine( WebConfig .ReportType.ToString());

sb.Append( "ReportSubject =" ).AppendLine( WebConfig .ReportSubject);

sb.Append( "DbLogin =" ).AppendLine( WebConfig .DbLogin);

sb.Append( "DbPass =" ).AppendLine( WebConfig .DbPass);



} catch例外 ex){

sb.AppendLine(ex.Message);

}



return sb.ToString();

}

これで、構成の読み取りをテストできます。



web_alpha.config


さらに、設定の一部を追加ファイルに配置する機能は非常に便利です。 たとえば、テスト環境と戦闘環境がデータベースへの接続文字列によって区別される場合。 また、設定の秘密部分を個別に保存することもできます。 この場合、繰り返される設定はこのファイルによって上書きされ、新しい設定もこのファイルで宣言できます。



web_alpha.configファイルをプロジェクトに追加します。

<? xml   バージョン = " 1.0 " ?>

< appSettings >

< 追加   key = " ReportSubject "   = "   ビジネス " />

< 追加   キー = " DbLogin "   =リーダー/>

< 追加   キー = " DbPass "   = " uYE4_wn7xc5Sp " />

</ appSettings >

そして、 web.config自体を次のように変更します。

<? xml   バージョン = " 1.0 " ?>

< 設定 >



< appSettings   file = " web_alpha.config " >

< 追加   キー = " ReportType "   = " 8 " />

< 追加   key = " ReportSubject "   =   ビジネス " />

</ appSettings >



< system.web >

< コンパイル   debug = " true "   targetFramework = " 4.0 " />

</ system.web >



</ 設定 >



web_beta.config


サードパーティのファイルも親フォルダに配置できます。 親フォルダーに新しいweb_beta.configファイルを作成します。

<? xml   バージョン = " 1.0 " ?>

< appSettings >

< 追加   key = " ReportSubject "   =   ビジネス " />

< 追加   キー = " DbLogin "   = " admin " />

< 追加   キー = " DbPass "   = " guXu4awewr $ w " />

</ appSettings >

それに応じてweb.configを変更します。

<? xml   バージョン = " 1.0 " ?>

< 設定 >



< appSettings   file = " .. /web_beta.config " >

< 追加   キー = " ReportType "   = " 8 " />

< 追加   key = " ReportSubject "   =   ビジネス " />

</ appSettings >



< system.web >

< コンパイル   debug = " true "   targetFramework = " 4.0 " />

</ system.web >



</ 設定 >



web_gamma.config


追加のファイルに設定を配置する別の方法があります。 web.configを次のように変更します。

<? xml   バージョン = " 1.0 " ?>

< 設定 >



< appSettings   configSource = " web_gamma.config " />



< system.web >

< コンパイル   debug = " true "   targetFramework = " 4.0 " />

</ system.web >



</ 設定 >

そして、 web_gamma.configファイルを作成します。

<? xml   バージョン = " 1.0 " ?>

< appSettings >

< 追加   キー = " ReportType "   = " 9 " />

< 追加   key = " ReportSubject "   =非営利/>

< 追加   キー = " DbLogin "   = " writer " />

< 追加   キー = " DbPass "   = " hQ5zGPPSrkqqfsb " />

</ appSettings >

このアプローチは、前のアプローチといくつかの重大な違いがあるため、柔軟性が低くなります。

  • 設定セクションのすべての値は、指定されたサードパーティファイルでのみ定義されます。 web.configの再定義はありません。
  • web_gamma.configファイルが存在する必要があります。web_alpha.configの場合は不要です。
  • その変更により、プールが再起動されますが、web_alpha.configの場合は再起動されません。
  • <appSettings>だけでなく、他のセクションにも適用可能




web.Debug.config


次に、Visual Studio 2010に登場したweb.configを操作するための別の便利なテクニックについて説明します。web.Debug.configファイルweb.Release.configファイルについて説明しています 。 これらのファイルは、現在のビルドの種類に応じて、 公開時に web.configを変換します。 これらのファイルの内容を次のように変更します。

<? xml   バージョン = " 1.0 " ?>

< 設定   xmlns xdt = " http :// スキーマ .microsoft.com / XML - Document - Transform " >



   < appSettings >

< 追加   key = " ReportSubject "   =デバッグ   xdt:Transform = " Replace "   xdt:Locator = " Match(key) " />

</ appSettings >



</ 設定 >

 



<? xml   バージョン = " 1.0 " ?>

< 設定   xmlns:xdt = " http://schemas.microsoft.com/XML-Document-Transform " >



< system.web >

< コンパイル   xdt:Transform = " RemoveAttributes (debug) " />

   </ system.web >

  

</ 設定 >



変換構文はMSDNで説明されています



ただし、構文を知らなくても、 Debugの場合はReportSubject設定値が置き換えられReleaseの場合はdebug =“ true”属性が削除されることを理解できます。 ところで、実稼働環境でdebug = "true"属性を削除するか、falseに設定することを忘れないでください。これにより、パフォーマンスとセキュリティが向上します。



さらに、 [ビルド]-> [構成マネージャー ]メニュー、およびweb.configファイルの[構成変換の追加 ]コンテキストメニューを使用して、独自のweb.Habr.config変換を作成できます。



MaxRequestLength


ASP.NETの一般的な設定から、着信要求の最大サイズの制限を選び出します。 これは、2つのパラメーターのうち小さい方と同じです。 さらに、maxRequestLengthはキロバイトで示され、maxAllowedContentLengthはバイトで示されます。 次に、100メガバイトの制限と30分間のクエリ実行を設定する例を示します。

<? xml   バージョン = " 1.0 " ?>

< 設定 >



< appSettings >

< 追加   キー = " ReportType "   = " 8 " />

< 追加   key = " ReportSubject "   =   ビジネス " />

</ appSettings >



  

< system.web >

<!- 100 mb   および 30 有効   のみ   compilation.debug = falseの 場合 ->

< httpRuntime   maxRequestLength = " 102400 "   executionTimeout = " 1800 " />



< コンパイル   targetFramework = " 4.0 " >

</ 編集 >

</ system.web >



< system.webServer >

< セキュリティ >

< requestFiltering >

<!- 100 mb- >

< requestLimits   maxAllowedContentLength = " 104857600 " />

</ requestFiltering >

</ セキュリティ >

</ system.webServer >



</ 設定 >





デフォルト値は4096 KBおよび30,000,000バイト、つまり4 MBおよび28.61 MBです



Web.config階層


実際、このweb.configは、構成ファイルの階層の一番下にあります。



最上位の構成はmachine.configファイルです 。 その設定は、下位レベルの設定ファイルによって上書きされない場合にのみ、すべてのWebアプリケーションにグローバルに適用されます。 .net 4プールの場合、ビット深度に応じて、 %windir%\ Microsoft.NET \ Framework \ v4.0.30319 \ Configまたは%windir%\ Microsoft.NET \ Framework64 \ v4.0.30319 \ Configフォルダーにあります



次のレベルもグローバルです-これは同じ場所にあるweb.configファイルです。



3番目のレベルはWebサイトレベルであり、デフォルトでは\ inetpub \ wwwrootフォルダーであり、最初はweb.configファイルはありません。



4番目はWebアプリケーション層であり、ここで説明する標準層です。



5番目のレベルもあります-web.config設定がWebアプリケーションのサブフォルダーに適用される場合ですが、これは他の種類のWebアプリケーションにも当てはまります。



MSDNで詳細を読むことができます



9.複数のasmxファイル



1つのWebアプリケーションには、1つではなく、複数のasmxファイルが存在できます。 明らかに、この方法で、いくつかの共通ソースコードを持ついくつかの異なるWebサービスを開発できます。 ただし、この手法は1つのWebサービスに使用できます。以下の例はその理由を示しています。



FinReportService.csファイルで、コードを次のように変更します。

システムを使用して ;

System.Configuration を使用します。

System.Web.Services を使用します。



名前空間 FinReportWebService {



[ WebServiceBinding (ConformsTo = WsiProfiles .BasicProfile1_1)]

[ WebService (説明= " Fin。Reports v.2" 、名前空間= XmlNS)]

パブリック クラス FinReportService_v2FinReportService {

public FinReportService_v2(): base (2){

}

}







[ WebServiceBinding (ConformsTo = WsiProfiles .BasicProfile1_1)]

[ WebService (説明= "CHECK: Fin。Reports " 、名前空間= FinReportService .XmlNS)]

パブリック クラス FinReportService_Check {

private FinReportService _service;



public FinReportService_Check(){

_service = new FinReportService ();

}



[ WebMethod (Description = " Enter   識別子   レポート 。 " )]

public GetReportResult GetReport( int reportID){

GetReportArg arg = new GetReportArg ();

arg.ReportID = reportID;

return _service.GetReport(arg);

}



[ WebMethod (説明= " 期間 2015年 1月 " )]

public GetReportIdArrayResult GetReportIdArray(){

GetReportIdArrayArg arg = new GetReportIdArrayArg ();

arg.DateBegin = new DateTime (2015、01、01);

arg.DateEnd = new DateTime (2015、02、01);

return _service.GetReportIdArray(arg);

}

}







[ WebServiceBinding (ConformsTo = WsiProfiles .BasicProfile1_1)]

[ WebService (説明= " Fin。Reports " 、名前空間= XmlNS)]

パブリック クラス FinReportServiceWebService {

public const string XmlNS = "http://asmx.habrahabr.ru/" ;

private int _version;



public FinReportService(){

_version = 1;

}



パブリック FinReportService( intバージョン){

_version =バージョン;

}



[ WebMethod (説明= " 取得   レポート ID リスト   によって   期間 " )]

public GetReportIdArrayResult GetReportIdArray( GetReportIdArrayArg arg){

新しい GetReportIdArrayResult ()を返す {

ReportIdArray = new int [] {357、358、360、361}

};

}



[ WebMethod (説明= " 取得   報告する   ID " )]で

public GetReportResult GetReport( GetReportArg arg){

新しい GetReportResult ()を返す {

レポート= 新しい FinReport {

ReportID = arg.ReportID、

日付= 新しい DateTime2015、03、15 )、

情報= "電話:" + ConfigurationManager .AppSettings [ "電話" ] + "バージョン:" + _version

}

};

}

}





パブリック クラス FinReport {

public int ReportID { get ; セット ; }

public DateTime Date { get ; セット ; }

パブリック ストリング Info { get ; セット ; }

}



パブリック クラス GetReportIdArrayArg {

public DateTime DateBegin { get ; セット ; }

パブリック DateTime DateEnd { get ; セット ; }

}



パブリック クラス GetReportIdArrayResult {

public int [] ReportIdArray { get ; セット ; }

}



パブリック クラス GetReportArg {

public int ReportID { get ; セット ; }

}



パブリック クラス GetReportResult {

公開 FinReportレポート{ get ; セット ; }

}



}

また、プロジェクトには次の3つのasmxファイルが必要です。

FinReport.asmx-変更なし:

<% @ Class = "FinReportWebService.FinReportService" %>

FinReport_v2.asmx-新規:

<% @ Class = "FinReportWebService.FinReportService_v2" %>

FinReport_CHECK.asmx-新規:

<% @ Class = "FinReportWebService.FinReportService_Check" %>

web.configの変更:

<? xml   バージョン = " 1.0 " ?>

< 設定 >



< system.web >

< コンパイル   debug = " true "   targetFramework = " 4.0 " />

</ system.web >



< appSettings >

< 追加   キー =電話  = " nokia " />

</ appSettings >

  



< 場所   path = " FinReport.asmx " >

< appSettings >

< 追加   キー =電話  = " samsung " />

</ appSettings >

</ 場所 >





< 場所   path = " FinReport_v2.asmx " >

< appSettings >

< 追加   キー =電話  = " htc " />

</ appSettings >

</ 場所 >



  

< 場所   path = " FinReport_CHECK.asmx " >

< appSettings >

< 追加   キー =電話  = " apple " />

</ appSettings >



< system.web >

< webServices >

< プロトコル >

< クリア />

< 追加   name = " Documentation " />

< 追加   name = " HttpPostLocalhost " />

</ プロトコル >

</ webServices >

</ system.web >

</ 場所 >



</ 設定 >

ご覧のとおり、2つの新しいasmxファイルは2つの新しいクラスを参照しています。 最初に、FinReportService_v2クラスの目的を説明します。 基本クラスとの唯一の機能的な違いは、デフォルトコンストラクターがint _versionフィールドを1ではなく値2で初期化することです。したがって、Webサービスにはまったく同じコントラクトを持つクローンがありますが、要求処理に違いがあります。 たとえば、このクローンはテスト用か、実際に新しいバージョンを提示するためのものです。



FinReportService_Checkクラスには、まったく異なる目的があります。 ご存知のように、localhostを使用してブラウザーでWebサービスを開くと、プリミティブな引数タイプを持つWebメソッドの場合、ブラウザー自体で直接クエリを実行して回答を確認できます。 これにより、管理者およびサーバーにアクセスできるすべてのユーザーが、サーバーが正しく機能していることを簡単に確認できます。









次に、構成ファイルについてコメントします。 デザインを使用して、特定のファイルの設定を上書きできます。 この場合、asmxファイルごとに「電話」のカスタム設定が異なります。



<protocols>セクションを使用して、最初にFinReport_CHECK.asmxと対話するすべての方法をクリアし、次にビューを追加して、localhostから呼び出します。 これにより、リモートアクセスができなくなります。



10. Webページの置換



デフォルトでは、ブラウザに表示されるWebサービスのasmx WebページはDefaultWsdlHelpGenerator.aspx Webフォームによって作成されます。x64の場合、%windir%\ Microsoft.NET \ Framework64 \ v4.0.30319 \ Configフォルダにあります。 。



ただし、web.configを使用すると、独自のaspxファイルを簡単に指定できます。 FinReportPage.aspxファイルをプロジェクトに追加します。

<! doctype html >

< html >

< >

< メタ 文字セット = utf-8>

< title >ようこそ</ title >

</ >

< 本体 >

< p >ようこそ! < / p >

</ body >

</ html >
そして、web.configで指定します

<? xml   バージョン = " 1.0 " ?>

< 設定 >

< system.web >



< webServices >

< wsdlHelpGenerator   href = " FinReportPage.aspx " />

</ webServices >



< コンパイル   debug = " true "   targetFramework = " 4.0 " />



</ system.web >

</ 設定 >




11.拡張機能の置き換え



web.configを使用すると、asmx拡張子を他のものに簡単に変更できます。 FinReportClone.habrなど、拡張子がhabrのファイルをFinReport.asmxと同じ内容でプロジェクトに追加します。 そして、構成を次のように変更します。

<? xml   バージョン = " 1.0 " ?>

< 設定 >

< system.web >

< コンパイル   debug = " true "   targetFramework = " 4.0 " >

< buildProviders >

< 削除   拡張子 = " .habr " />

< 追加   拡張子 = " .habr "   type = " System.Web.Compilation.WebServiceBuildProvider " />

</ buildProviders >

</ 編集 >

</ system.web >



< system.webServer >

< ハンドラー >

< 追加   name = " HabraHandler "   動詞 = " * "   path = " * .habr "   type = " System.Web.Services.Protocols.WebServiceHandlerFactory " />

</ ハンドラー >

</ system.webServer >

  

</ 設定 >

Visual Studioから起動する場合、FinReportClone.habrは機能しないため、IISに公開する必要があることに注意してください。 ところで、この手法を使用すると、元のURLを維持しながら、ASMX WebサービスをWCF Webサービスに置き換えることができます。



12. wsdlを非表示



デフォルトでは、URLにWsdlを追加すると、SOAP Webサービスのwsdl記述が使用可能になります。 これは、このアドレスを知っていて見れば誰でも簡単にそのWebメソッドを呼び出すことができることを意味します。 また、認証メカニズムがない場合は、非常に危険です。 ただし、そのようなメカニズムがあっても、Webサービスの契約を示すことは一般的に望ましくありません。



1つの方法。 次の設定をweb.configに追加します。

   < system.web >

< webServices >

< プロトコル >

< 削除   name = " Documentation " />

       </ プロトコル >

</ webServices >

</ システム ウェブ >

これは、Webサービスに関する情報を非表示にする標準的な方法です。 基本的に、GETリクエストを禁止するだけです。 ブラウザーでアドレスを開こうとすると例外がスローされますが、WebメソッドのPOSTリクエストは通常​​どおり機能します。 このメソッドの重大ではないマイナスは、ブラウザがエラーを表示することです。







2通り。 GET要求は、カスタムHTTPハンドラーを使用してインターセプトできます。 次のクラスをプロジェクトに追加します。

System.Web を使用

名前空間 FinReportWebService {

パブリック クラス FinReportGetHandlerIHttpHandler {

public void ProcessRequest( HttpContext context){

文字列応答=

@ "<!doctype html>

<html>

<head>

<メタ文字セット= utf-8>

</ head>

<本体>

<p> {0} </ p>

</ body>

</ html> " ;



bool wsdlRequested =(context.Request.QueryString.ToString()。ToLower()== "wsdl" );



if (wsdlRequested){

response = string .Format(response、 " 連絡先     管理者へ   wsdlの場合。 " );

} else {

response = string .Format(response、 " Web サービス   金銭的   レポート 。 " );

}



context.Response.ContentType = "text / html; charset = utf-8" ;

context.Response.Write(応答);



// string filePage = HttpContext.Current.Server.MapPath( "〜/ FinReportPage.htm");

// context.Response.WriteFile(filePage);

}



パブリック bool IsReusable {

get { falseを返す ; }

}

}

}
そして、web.configを変更します:

<? xml   バージョン = " 1.0 " ?>

< 設定 >

  

< system.web >

< コンパイル   debug = " true "   targetFramework = " 4.0 " >

</ 編集 >

</ system.web >



< system.webServer >

< ハンドラー >

< 追加   name = " FinReportGetHandler "   動詞 = " GET "   path = " FinReport.asmx "   type = " FinReportWebService.FinReportGetHandler " />

     </ ハンドラー >

</ system.webServer >

  

</ 設定 >



前のトリックのように、ハンドラーはIISでのみ機能します。 ちなみに、Webページをハードコードするのではなく、ファイルから読み取ることをお勧めします。



13.例外



Webサービスでの例外処理は常に非常に重要です。 エラーを特定して返すための成功したメカニズムを構築すると、両側の開発者にとって多くの時間と神経を節約できます。 以下は、何かがうまくいかなかったことをWebサービスクライアントに知らせる2つの異なる方法です。



<石鹸:障害>


<soap:Fault>要素は、エラーを返すための標準のSOAPメソッドです。 4つのサブ要素で構成されます。

  • <faultcode>-エラーコード
  • <faultstring>-人間が読めるエラーの説明
  • <faultactor>-エラーの原因
  • <detail>-詳細データの任意のXML構造


<faultcode>と<faultstring>は必須ですが、他の2つはオプションです。

それを実証するには、getReportInfoメソッドを次のコードに変更します。

プライベート 文字列 getReportInfo( int reportID){

throwException_1();

// throwException_2();

// throwException_3();

return "ReportID =" + reportID;

}





private void throwException_1(){

int x = 0;

x = 1 / x;

}





private void throwException_2(){

新しい SoapException 無効な ReportID」SoapException .ClientFaultCode、Context.Request.Url.AbsoluteUri)をスローします。

}





private void throwException_3(){

XmlDocument xmlDoc = new XmlDocument ();

XmlNode rootNode = xmlDoc.CreateNode( XmlNodeType .Element、 SoapException .DetailElementName.Name、 SoapException .DetailElementName.Namespace);



XmlNode descNode = xmlDoc.CreateNode( XmlNodeType .Element、 "Description" 、XmlNS);



XmlNode descTypeNode = xmlDoc.CreateNode( XmlNodeType .Element、 "Type" 、XmlNS);

descTypeNode.InnerText = "DbConnection" ;

descNode.AppendChild(descTypeNode);



XmlNode descMessageNode = xmlDoc.CreateNode( XmlNodeType .Element、 "Message" 、XmlNS);

descMessageNode.InnerText = " ホスト   じゃない   見つかりました 。 " ;

descNode.AppendChild(descMessageNode);



XmlNode habraNode = xmlDoc.CreateNode( XmlNodeType .Element、 "HabraInfo" 、XmlNS);

XmlAttribute habraNodeAttribute = xmlDoc.CreateAttribute( "User" );

habraNodeAttribute.Value = "capslocky" ;

habraNode.Attributes.Append(habraNodeAttribute);



rootNode.AppendChild(descNode);

rootNode.AppendChild(habraNode);



XmlQualifiedName faultCode = new XmlQualifiedName"TempError" 、XmlNS);

新しい SoapException" 一時的な   エラー 、faultCode、Context.Request.Url.AbsoluteUri、rootNode);

}

throwException_1()でGetReport Webメソッドを呼び出します。このメソッドでは、未処理のゼロ除算エラーが生成されます。 この場合のASP.NET DevServer(またはIIS)は、「200 OK」の代わりにhttpコード「500 Internal Server Error」と、便宜上フォーマットされた次のコンテンツを返します。

 

<? xml   バージョン = " 1.0 "   エンコーディング = " UTF-8 " ?>

< 石鹸:封筒   xmlns:soap = " http://schemas.xmlsoap.org/soap/envelope/ "   xmlns:xsd = " http://www.w3.org/2001/XMLSchema "   xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance " >

< 石鹸: ボディ >

< soap: 障害 >

< faultcode > soap:サーバー</ faultcode >

< faultstring >サーバーは要求を処理できませんでした。 --- &gt; ゼロで除算しようとしました。 < / faultstring >

< 詳細 />

</ soap:障害 >

</ 石鹸:ボディ >

</ 石鹸:封筒 >

未処理の例外は、常にsoap:Serverを提供します。 例外スタックの表示は、customErrors設定によって異なります。

 

<? xml   バージョン = " 1.0 " ?>

< 設定 >

  

< system.web >

< コンパイル   debug = " true "   targetFramework = " 4.0 " />

< customErrors   モード =オン/>

</ system.web >

  

</ 設定 >

mode属性には、次の3つの値のみがあります。

  • オン-スタックを表示しない
  • オフ-常に表示
  • RemoteOnly-ローカルホスト要求に対してのみ表示


SoapExceptionを手動でスローすることにより、<soap:Fault>構造を自分で定義できます。 throwException_2メソッドを呼び出します。 このコードは、次の応答コンテンツになります

<? xml   バージョン = " 1.0 "   エンコーディング = " UTF -8 " ?>

< 石鹸:封筒   xmlns:soap = " http://schemas.xmlsoap.org/soap/envelope/ "   xmlns:xsd = " http://www.w3.org/2001/XMLSchema "   xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance " >

< 石鹸: ボディ >

< soap: 障害 >

< faultcode > soap:クライアント</ faultcode >

< faultstring > 無効な ReportID </ faultstring >

< faultactor > http://win2012/custom_folder/FinReport.asmx </ faultactor >

< 詳細 />

</ soap:障害 >

</ 石鹸:ボディ >

</ 石鹸:封筒 >

ここでは、エラーコードを変更し、説明テキストを記述し、リクエストURLが通常示されている場所も示しています。

一般に、SoapExceptionクラスの静的フィールドで表される4つの標準障害コードがあります。

  • サーバー-Webサービス自体の問題
  • クライアント-クライアントが無効なリクエストを送信しました
  • MustUnderstand-soapを処理するためのリモート性ではない:ヘッダー、処理が必須
  • VersionMismatch-不適切なSOAPバージョン


throwException_3()メソッドは、独自の<detail>およびエラーコードの形成を示します。

<? xml   バージョン = " 1.0 "   エンコーディング = " UTF-8 " ?>

< 石鹸:封筒   xmlns:soap = " http://schemas.xmlsoap.org/soap/envelope/ "   xmlns:xsd = " http://www.w3.org/2001/XMLSchema "   xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance " >

< 石鹸: ボディ >

< soap: 障害 >

< faultcode   xmlns:q0 = " http://asmx.habrahabr.ru/ " > q0:TempError </ faultcode >

< faultstring >一時的なエラー</ faultstring >

< faultactor > http://win2012/custom_folder/FinReport.asmx </ faultactor >

< 詳細 >

< 説明   xmlns = " http://asmx.habrahabr.ru/ " >

< タイプ > DbConnection </ タイプ >

< メッセージ >ホストが見つかりません。 < / メッセージ >

</ 説明 >

< HabraInfo   xmlns = " http://asmx.habrahabr.ru/ "   ユーザー = " capslocky " />

</ 詳細 >

</ soap:障害 >

</ 石鹸:ボディ >

</ soap 封筒 >

ただし、Webメソッドで未処理の例外が発生する可能性をまったく許可しないことをお勧めします。 つまり、メソッドには常にグローバルなtry-catchが必要です。これは、未処理または手動でスローされた例外をキャッチし、事前に定義された形式でクライアントに返します。



列挙型


このメソッドのアイデアは、列挙を使用して、クライアントにリクエストの処理の成功または失敗を通知することです。 すべての列挙値がwsdlに反映されることが重要です。したがって、それらはクライアントプロキシクラスに自動的に存在します。



FinReport_GetReport.csファイルをプロジェクトに追加します。

システムを使用して ;



名前空間 FinReportWebService {



パブリック クラス WebServiceError {

public ErrorType Type { get ; セット ; }

パブリック ストリングメッセージ{ get ; セット ; }

}





パブリック 列挙型 ResultType {

エラー、

FoundBasicData、

FoundFullData

}





public enum ErrorType {

未定義

Dbconnection

InvalidArgument、

禁じられた

}





パブリック クラス WebServiceErrorExceptionException {

public WebServiceErrorエラー{ get ; セット ; }

}





パブリック クラス FinReport_GetReport {

private GetReportArg _arg;

プライベート GetReportResult _result;



public GetReportResult GetReport( GetReportArg arg){

_arg = arg;

initializeResultWithError();



{

checkArg();

fillResult();



} catchWebServiceErrorException ex){

setResultType( ResultType .Error);

_result.Error = ex.Error;



} catch例外 ex){

setResultType( ResultType .Error);

_result.Error.Type = ErrorType .Undefined;

_result.Error.Message = ex.GetType()+ ":" + ex.Message;

}



if (_result.ResultType == ResultType .Error){

_result.Report = null ;



} else {

_result.Error = null ;

}



return _result;

}





private void setResultType( ResultTypeタイプ){

_result.ResultType = type;

}





private void initializeResultWithError(){

_result = new GetReportResult ();

setResultType( ResultType .Error);



_result.Error = new WebServiceError ();

_result.Error.Type = ErrorType .Undefined;

_result.Error.Message = "結果が指定されていません" ;

}





private void checkArg(){

if (_arg.ReportID <= 0){

throw 新しい WebServiceErrorException (){

エラー= new WebServiceError (){

タイプ= ErrorType .InvalidArgument、

メッセージ= " 無効   識別子   レポート : " + _arg.ReportID

}

};

}

}





private void fillResult(){

_result.Report = new FinReport ();

_result.Report.ReportID = _arg.ReportID;

_result.Report.Date = new DateTime (2015、03、15);



//新しいWebServiceErrorException()をスローします{

//エラー= new WebServiceError(){

//タイプ= ErrorType.DbConnection、

//メッセージ= " ホスト   引き裂いた   接続

//}

//};



//新しいInvalidOperationException( " Oops ")を スローし ます;



_result.Report.Info = "Some info" ;

setResultType( ResultType .FoundFullData);

}



}

}

GetReport Webメソッドの修正

[ WebMethod (説明= 「IDによるレポートの取得」 )]

public GetReportResult GetReport( GetReportArg arg){

return new FinReport_GetReport ().GetReport(arg);

}

GetReportResult

public class GetReportResult {

public ResultType ResultType { get ; set ; }

public WebServiceError Error { get ; set ; }

public FinReport Report { get ; set ; }

}

, ResultType , - . . . «200 OK» GetReportResult.



:

<? xml   version = " 1.0 "   encoding = " UTF-8 " ?>

< soap:Envelope   xmlns:soap = " http://schemas.xmlsoap.org/soap/envelope/ "   xmlns:xsd = " http://www.w3.org/2001/XMLSchema "   xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance " >

< soap: Body >

< GetReportResponse   xmlns = " http://asmx.habrahabr.ru/ " >

< GetReportResult >

< ResultType > FoundFullData </ ResultType >

< Report >

< ReportID > 45 </ ReportID >

< Date > 2015-03-15T00:00:00 </ Date >

< Info > Some info </ Info >

</ Report >

</ GetReportResult >

</ GetReportResponse >

</ soap:Body >

</ soap:Envelope >

 

 

<? xml   version = " 1.0 "   encoding = " UTF-8 " ?>

< soap:Envelope   xmlns:soap = " http://schemas.xmlsoap.org/soap/envelope/ "   xmlns:xsd = " http://www.w3.org/2001/XMLSchema "   xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance " >

< soap: Body >

< GetReportResponse   xmlns = " http://asmx.habrahabr.ru/ " >

< GetReportResult >

< ResultType > Error </ ResultType >

< Error >

< Type > DbConnection </ Type >

< Message > </ Message >

</ Error >

</ GetReportResult >

</ GetReportResponse >

</ soap:Body >

</ soap:Envelope >

 

 

<? xml   version = " 1.0 "   encoding = " UTF-8 " ?>

< soap:Envelope   xmlns:soap = " http://schemas.xmlsoap.org/soap/envelope/ "   xmlns:xsd = " http://www.w3.org/2001/XMLSchema "   xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance " >

< soap: Body >

< GetReportResponse   xmlns = " http://asmx.habrahabr.ru/ " >

< GetReportResult >

< ResultType > Error </ ResultType >

< Error >

< Type > Undefined </ Type >

< Message > System.InvalidOperationException: </ Message >

</ Error >

</ GetReportResult >

</ GetReportResponse >

</ soap:Body >

</ soap:Envelope >





<? xml   version = " 1.0 "   encoding = " UTF-8 " ?>

< soap:Envelope   xmlns:soap = " http://schemas.xmlsoap.org/soap/envelope/ "   xmlns:xsd = " http://www.w3.org/2001/XMLSchema "   xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance " >

< soap: Body >

< GetReportResponse   xmlns = " http://asmx.habrahabr.ru/ " >

< GetReportResult >

< ResultType > Error </ ResultType >

< Error >

< Type > InvalidArgument </ Type >

< Message > : -245 </ Message >

</ Error >

</ GetReportResult >

</ GetReportResponse >

</ soap:Body >

</ soap:Envelope >

, http- -, - , soap:Fault .



14. soap:Header



SOAP . , , , - .



- :

システムを使用して ;

using System.Text;

using System.Web.Services;

using System.Web.Services.Protocols;



namespace FinReportWebService{



[ WebServiceBinding (ConformsTo = WsiProfiles .BasicProfile1_1)]

[ WebService (Description = " . " , Namespace = XmlNS)]

public class FinReportService : WebService {

public const string XmlNS = "http://asmx.habrahabr.ru/" ;



public HabraSoapHeader HabraHeader { get ; set ; }

public ResultTimeSoapHeader ResultTimeHeader { get ; set ; }

public SoapUnknownHeader [] UnknownHeaders { get ; set ; }





[ SoapHeader ( "HabraHeader" )] //    

[ SoapHeader ( "ResultTimeHeader" , Direction = SoapHeaderDirection .Out)]

[ SoapHeader ( "UnknownHeaders" )]

[ WebMethod (Description = "     ID" )]

public GetReportResult GetReport( GetReportArg arg) {

// throw new SoapHeaderException(" ", SoapException.ClientFaultCode);

return new GetReportResult () {

Report = new FinReport {

ReportID = arg.ReportID,

Date = new DateTime (2015, 03, 15),

Info = getReportInfo(arg.ReportID)

}

};

}





private string getReportInfo( int reportID) {

StringBuilder sb = new StringBuilder ();

sb.Append( "ReportID = " ).Append(reportID).AppendLine();



if (HabraHeader != null ) {

sb.Append( "Login = " ).Append(HabraHeader.Login).AppendLine();

sb.Append( "Password = " ).Append(HabraHeader.Password).AppendLine();

}



foreach ( var header in UnknownHeaders) {

sb.Append( " SoapHeader = " ).Append(header.Element.Name).AppendLine();

sb.Append( "MustUnderstand = " ).Append(header.MustUnderstand).AppendLine();



// if (header.Element.Name == "HabraSoapHeader") {

// sb.AppendLine("HabraSoapHeader ");

// sb.Append("Login = ").Append(header.Element["Login"].InnerText).AppendLine();

// sb.Append("Password = ").Append(header.Element["Password"].InnerText).AppendLine();

// header.DidUnderstand = true;

// }

}



ResultTimeHeader = new ResultTimeSoapHeader ();

ResultTimeHeader.ResultTime = DateTime .Now;

return sb.ToString();

}

}





public class HabraSoapHeader : SoapHeader {

public string Login { get ; set ; }

public string Password { get ; set ; }

}





public class ResultTimeSoapHeader : SoapHeader {

public DateTime ResultTime { get ; set ; }

}





public class FinReport {

public int ReportID { get ; set ; }

public DateTime Date { get ; set ; }

public string Info { get ; set ; }

}





public class GetReportArg {

public int ReportID { get ; set ; }

}





public class GetReportResult {

public FinReport Report { get ; set ; }

}

}
- -, wsdl. :

private void webMethodTest_GetReport() {

var service = GetFinReportService();

var arg = new GetReportArg ();

arg.ReportID = 45;



service.HabraSoapHeaderValue = new HabraSoapHeader ();

service.HabraSoapHeaderValue.Login = "neo" ;

service.HabraSoapHeaderValue.Password = "3Ku2kcQfNLOW" ;

service.HabraSoapHeaderValue.MustUnderstand = true ;



var result = service.GetReport(arg);

var resultTimeSoapHeader = service.ResultTimeSoapHeaderValue;



if (resultTimeSoapHeader != null ) {

MessageBox .Show( "ResultTimeSoapHeader = " + resultTimeSoapHeader.ResultTime);

}



MessageBox .Show(result.Report.Info);

}



, asmx - soap, :

  • SoapHeader
  • - [SoapHeader],


- – HabraSoapHeader ResultTimeSoapHeader, , .



:

<? xml   version = " 1.0 "   encoding = " UTF-8 " ?>

< soap:Envelope   xmlns:soap = " http://schemas.xmlsoap.org/soap/envelope/ "   xmlns:xsd = " http://www.w3.org/2001/XMLSchema "   xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance " >

< soap: Header >

< HabraSoapHeader   xmlns = " http://asmx.habrahabr.ru/ "   soap:mustUnderstand = " 1 " >

< Login > neo </ Login >

< Password > 3Ku2kcQfNLOW </ Password >

</ HabraSoapHeader >

</ soap:Header >

< soap: Body >

< GetReport   xmlns = " http://asmx.habrahabr.ru/ " >

< arg >

< ReportID > 45 </ ReportID >

</ arg >

</ GetReport >

</ soap:Body >

</ soap:Envelope >



<? xml   version = " 1.0 "   encoding = " UTF-8 " ?>

< soap:Envelope   xmlns:soap = " http://schemas.xmlsoap.org/soap/envelope/ "   xmlns:xsd = " http://www.w3.org/2001/XMLSchema "   xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance " >

< soap: Header >

< ResultTimeSoapHeader   xmlns = " http://asmx.habrahabr.ru/ " >

< ResultTime > 2015-03-24T11:37:00.6135717+06:00 </ ResultTime >

</ ResultTimeSoapHeader >

</ soap:Header >

< soap: Body >

< GetReportResponse   xmlns = " http://asmx.habrahabr.ru/ " >

< GetReportResult >

< Report >

< ReportID > 45 </ ReportID >

< Date > 2015-03-15T00:00:00 </ Date >

< Info >

ReportID = 45

Login = neo

Password = 3Ku2kcQfNLOW

</ Info >

</ Report >

</ GetReportResult >

</ GetReportResponse >

</ soap:Body >

</ soap : Envelope >

 

soap:mustUnderstand=«1», , - . SoapHeader public bool DidUnderstand { set; 取得; }, , . true, – false. , mustUnderstand=«1», DidUnderstand false, - soap:Fault. [SoapHeader(«HabraHeader»)], :

<? xml   version = " 1.0 "   encoding = " UTF-8 " ?>

< soap:Envelope   xmlns:soap = " http://schemas.xmlsoap.org/soap/envelope/ "   xmlns:xsd = " http://www.w3.org/2001/XMLSchema "   xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance " >

< soap: Body >

< soap: Fault >

< faultcode > soap:MustUnderstand </ faultcode >

< faultstring > SOAP HabraSoapHeader . </ faultstring >

</ soap:Fault >

</ soap:Body >

</ soap:Envelope >

public SoapUnknownHeader[] UnknownHeaders { get; セット; }, foreach.



SoapExtension. -. . - ( -), .



, , , SoapHeaderException, SoapException. , , , SoapException, soap:Fault. .



15.



asmx - . CacheDuration -, HttpContext.Cache . :

[ WebMethod (Description = "     ID" , CacheDuration = 5)]

public GetReportResult GetReport( GetReportArg arg){

return new GetReportResult (){

Report = new FinReport {

ReportID = arg.ReportID,

Date = DateTime .Now,

Info = getReportInfo(arg.ReportID)

}

};

}





private string getReportInfo( int reportID){

string key = "getReportInfo_" + reportID;

string cachedInfo = Context.Cache.Get(key) as string ;



if (cachedInfo != null ){

return cachedInfo;

}



string info = DateTime .Now + " reportID = " + reportID;

this .Context.Cache.Add(key, info, null , DateTime .Now.AddSeconds(10), TimeSpan .Zero, CacheItemPriority .High, null );

return info;

}

soap . , - , .



, .



, Date 5 , Info – 10 .



, , .



16. SoapExtension



SoapExtension – , , -, . , , .



SoapExtension:

  • ( soap MemoryStream)
  • (soap header)
  • 1 : - (- )
  • 2 : - ( ) web.config (app.config) !
  • - -
  • SoapExtension


SoapExtension

  • soap header


参照資料





17. x64 Visual Studio



- Visual Studio 64- -. Platform target: x64, « «FinReportWebService» . , ».



.



1 . - «Use Local IIS Web server», IIS







2 . - IIS Debug -> Attach to Process .



3 . IIS ASP.NET Development Server - CassiniDev . CassiniDev : https://cassinidev.codeplex.com/SourceControl/latest#ReadMe.htm



, \trunk\src\CassiniDev.sln, trunk\src\packages. x64 :







- C:\Program Files (x86)\Common Files\microsoft shared\DevServer . , \trunk\src\CassiniDev\bin\x64\Debug







18. ()



Publish File System Visual Studio , IIS







wwwroot


- C:\inetpub\wwwroot , -. , IIS inetmgr .











HTTP Error 404.3 — Not Found


HTTP Error 404.3 — Not Found, IIS









%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_regiis.exe –ir





-







- IIS :

HTTP Error 500.19 — Internal Server Error.

The requested page cannot be accessed because the related configuration data for the page is invalid.

または

アクセスが拒否されました。

Error message 401.3: You do not have permission to view this directory or page using the credentials you supplied

.



19. IIS



- . . FinReportPool -.





ApplicationPoolIdentity :

IIS AppPool\< >



, IIS AppPool\FinReportPool , IIS AppPool\DefaultAppPool



,















, < >\IIS_IUSRS



.







, x86/x64

«FinReportWebService» . , .
Could not load file or assembly 'FinReportWebService' or one of its dependencies. An attempt was made to load a program with an incorrect format.

- Enable 32-Bit Applications .



Identity -.



AppCmd.exe


w3wp.exe. :

AppcmdList.bat

%systemroot%\System32\inetsrv\appcmd list wp

%systemroot%\System32\inetsrv\appcmd list sites

%systemroot%\System32\inetsrv\appcmd list app

%systemroot%\System32\inetsrv\appcmd list appPools

pause







, , -. AppCmd.exe .



20.



-, , .




All Articles