Приемы разработки ASMX веб-сервисов

2952c2714f3e49a5be5d2d05452f938e.jpgВ этой статье я расскажу о различных приемах разработки SOAP веб-сервисов по технологии ASMX, а также об этой технологии в целом. Кроме SOAP, также будет рассмотрена реализация AJAX. Статья будет полезна как тем, кто уже знаком с ней, так и тем, кто только собирается создать свой первый веб-сервис.СодержаниеИсторическая справкаASMX и WCFВведениеПростейшая конструкция Рекомендуемая конструкция Прокси-класс с помощью wsdl.exe Серверный класс по данному wsdl ajax Метаданные запроса Обращение к файлам web.config Множественные asmx файлы Замена веб-страницы Замена расширения Скрытие wsdl Исключения soap: Header Кэширование SoapExtension Дебаггинг x64 в Visual Studio Деплой (публикация) Пулы приложений IIS Инструменты разработки Историческая справка С самого начала корпорация Microsoft была одним из основных разработчиков стандарта SOAP. В 2002 году в составе самой первой версии ASP.NET 1.0 она представила технологию ASMX (Active Server Method Extended), которая позволила разработчикам в новейшей Visual Studio 2002 легко создавать и потреблять SOAP веб-сервисы. Отмечу, что эта технология официально на MSDN имеет название «XML Web Services». В те годы SOAP только делал первые серьезные шаги в мире веб-разработки. Консорциум W3C одобрил SOAP 1.1 в 2000 году, SOAP 1.2 в 2003 году (дополнен в 2007 году). Поэтому было очень важно сделать для нового стандарта легкую в освоении и применении технологию. И эта цель была достигнута — чтобы работать с веб-сервисами, разработчику даже не обязательно было знать XML, SOAP и WSDL.В последующие годы технология ASMX получила очень широкое распространение и признание. Также с самого начала Microsoft поставляла к ней аддон Web Services Enhancements (WSE), который позволял реализовывать различные спецификации безопасности WS-* такие, как WS-Security, WS-Policy, WS-ReliableMessaging. Последняя версия — WSE 3.0 вышла в 2005 году. А в 2007 году в составе .NET 3.0 была представлена технология Windows Communication Foundation (WCF), которая стала официальной заменой ASMX. Несмотря на то, что технология ASMX уже давно не развивается, она продолжает широко использоваться и поддерживается новейшими версиями .NET Framework.

ASMX и WCF Интересно сравнить, сколько веб-сервисов обоих типов видит Google: 314 000 ASMX и 6 280 WCFПочему же технология ASMX все еще так популярна? Все очень просто: она легка в применении и прекрасно решает задачу в большинстве случаев. Преимущество WCF проявляется, например, в тех случаях, когда вам нужна высокая скорость транспорта, дуплекс, потоковая передача, соблюдение современных стандартов безопасности, REST. Кстати, если вам нужен только REST, то вместо WCF стоит использовать технологию ASP.NET Web API.Перечислим конкретно плюсы каждой технологии: Плюсы ASMX:

Легкость в разработке Легкость в изучении Нет «ада» конфигурирования Плюсы WCF: Очень разнообразные и гибкие возможности транспорта Актуальная и развивающаяся технология Различные варианты хостинга Возможность реализации большого множества стандартов WS-* Итак, WCF — это «швейцарский нож» в области транспорта данных, а ASMX — «добротная отвертка». И лучше всего, конечно, уметь пользоваться обоими инструментами. Поскольку приемы разработки WCF в интернете описаны более полно и актуально, я решил, что нужно написать статью про ASMX, которая пригодится тем, кому приходится поддерживать старые веб-сервисы, и тем, кто продолжает применять эту технологию для создания новых.51282b84011948e798d8860f8060b45f.jpg Введение В статье описаны 20 различных практических приемов, которые можно применить при разработке веб-сервисов по данной технологии. Сценарий для примеров будет следующий. Имеется регулярно пополняемая база данных финансовых отчетов. Необходимо разработать универсальный механизм, с помощью которого у различных клиентов всегда будут актуальные данные по этим отчетам. Решение: пишем SOAP веб-сервис с двумя методами: Первый метод принимает период во времени и возвращает идентификаторы всех отчетов, которые появились в этом периоде Второй метод принимает идентификатор отчета и возвращает сами данные по отчету Потребители веб-сервиса регулярно шлют запросы к первому методу, указывая период с момента их последнего запроса, и при наличии в ответе идентификаторов, запрашивают данные через второй метод.Примеры демонстрируются на основе кода из «Рекомендуемой конструкции», и чтобы их протестировать достаточно вызвать веб-метод GetReportInfo как показано в примере «Прокси-класс».

1. Простейшая конструкция Начнем с описания простейшей конструкции веб-сервиса. Внимание, пример носит исключительно теоретический характер! Хоть он и рабочий, никогда так не делайте на практике. Это только демонстрация простоты самой технологии ASMX.Создайте в Visual Studio новый проект «ASP.NET Empty Web Application» или «ASP.NET Web Service Application» с именем FinReportWebService. Добавьте в него два файла: FinReport.asmx и FinReportService.cs, причем FinReport.asmx добавьте как Text File, а не Web Service, чтобы это был одиночный файл.

FinReport.asmx

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

FinReportService.cs using System; using System.Web.Services;  namespace FinReportWebService{     public class FinReportService {        [WebMethod]        public int[] GetReportIdArray (DateTime dateBegin,  DateTime dateEnd){            int[] array = new int[] {357,  358,  360,  361};             return array;         }         [WebMethod]        public FinReport GetReport (int reportID){            FinReport finReport = new FinReport (){                ReportID = reportID,                  Date = new DateTime (2015,  03,  15),                  Info = «Some info»            };              return finReport;         }    }     public class FinReport {        public int ReportID { get;  set;  }        public DateTime Date { get;  set;  }        public string Info { get;  set;  }    }}

Нажмите F5 для запуска веб-сервера и откройте в браузере FinReport.asmx, вы должны увидеть47d6094d57bb43b4b2917ca3ee77feee.png

Готово. Теперь разберем по порядку. Веб-сервис представлен одним обычным классом с одной лишь обязательной особенностью — некоторые его методы помечены специальным атрибутом [WebMethod]. Такие методы класса становятся веб-методами веб-сервиса с соответствующей сигнатурой вызова. Этот класс должен обладать конструктором по умолчанию. При каждом новом запросе IIS его инстанциирует дефолтным конструктором и вызывает соответствующий метод.

Вторая обязательная часть минимальной конструкции — это файл с расширением asmx, внутри которого необходимо указать этот класс.

Интересно сравнить этот вручную созданный asmx файл с тем, который создаст Visual Studio. Предположим, что мы хотим сделать еще один веб-сервис, который возвращает курс обмена валют. Добавьте через меню Add New Item файл ExchangeRate.asmx с типом Web Service.

bae65f90f6f64897a28fb83104a8a4b8.png

Нажав один-два раза на F7, можно увидеть следующее:

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

Оператор Language=«C#» является рудиментарным, и нужен только если вы будете писать исходный код непосредственно внутри asmx файла. Такой код будет компилироваться динамически. Но я считаю, что в целом динамическая компиляция веб-сервиса — не очень хорошая практика, и в частности, не рекомендую использование специальной папки App_Code. А оператор CodeBehind=«ExchangeRate.asmx.cs» просто связывает два файла на уровне Visual Studio.2. Рекомендуемая конструкция В этом примере тот же самый веб-сервис реализован более корректным образом. Хотя это и более правильный код, он также служит только для демонстрации. Например, здесь пропущены такие важные стандартные вещи как авторизация, обработка исключений, логирование. Также этот пример будет основой, на которой будут демонстрироваться другие приемы этой статьи. В файле FinReportService.cs содержимое замените на следующий исходный код: FinReportService.cs

using System; using System.Web.Services; using System.Xml.Serialization;  namespace FinReportWebService{     [WebServiceBinding (ConformsTo = WsiProfiles.BasicProfile1_1)]    [WebService (Description = «Фин. отчеты»,  Namespace = XmlNS)]    public class FinReportService :  WebService{        public const string XmlNS = «http://asmx.habrahabr.ru/»;          [WebMethod (Description = «Получение списка ID отчетов по периоду»)]        public GetReportIdArrayResult GetReportIdArray (GetReportIdArrayArg arg){            return new GetReportIdArrayResult (){                ReportIdArray = new int[] {357,  358,  360,  361}            };         }         [WebMethod (Description = «Получение отчета по ID»)]        public GetReportResult GetReport (GetReportArg arg){            return new GetReportResult (){                Report = new FinReport{                    ReportID = arg.ReportID,                     Date = new DateTime (2015,  03,  15),                     Info = getReportInfo (arg.ReportID)                }            };         }         private string getReportInfo (int reportID){            return «ReportID = » + reportID;         }    }  //    [Serializable]//    [XmlType (Namespace = FinReportService.XmlNS)]    public class FinReport {        public int ReportID { get;  set;  }        public DateTime Date { get;  set;  }        public string Info { get;  set;  }    }     public class GetReportIdArrayArg {        public DateTime DateBegin { get;  set;  }        public DateTime DateEnd { get;  set;  }    }     public class GetReportIdArrayResult {        public int[] ReportIdArray { get;  set;  }    }     public class GetReportArg {        public int ReportID { get;  set;  }    }     public class GetReportResult {        public FinReport Report { get;  set;  }    }}

Разберем изменения.Атрибут [WebServiceBinding (ConformsTo = WsiProfiles.BasicProfile1_1)] означает, что веб-сервис проверяется на соответствие спецификации WSI Basic Profile 1.1. Например, согласно ней запрещена перегрузка имени операции, или применение атрибута [SoapRpcMethod]. Такие нарушения будут приводить к ошибке веб-сервиса «Служба «FinReportWebService.FinReportService» не отвечает спецификации Simple SOAP Binding Profile Version 1.0.». При отсутствии этого атрибута нарушения будут приводить только к предупреждению «Эта веб-служба не отвечает требованиям WS-I Basic Profile v1.1.». В общем случае рекомендуется добавлять этот атрибут, что обеспечивает большую интероперабельность.Атрибут [WebService (Description = «Фин. отчеты», Namespace = XmlNS)] имеет всего три свойства: Namespace — дефолтный ХМЛ нэймспейс — указывать обязательноDescription — описание веб-сервиса, отображаемое в браузереName — имя веб-сервиса (по дефолту берется имя класса)

Наследование от класса WebService дает доступ к объектам HttpContext, HttpSessionState и некоторым другим, что в некоторых случаях может быть полезно.

В атрибуте [WebMethod (Description = «Получение отчета по ID»)] как правило указывают только Description, который описывает веб-метод в браузере, другие свойства используются редко.

Входящие параметры и возвращаемые значения я лично рекомендую инкапсулировать в специальные классы. Например, я их называю, добавляя суффиксы -Arg и -Result к названию метода, что означает аргумент и результат. В этом примере для упрощения они все находятся в одном файле FinReportService.cs, но в реальных проектах каждый из них я размещаю в отдельном файле в специальной папке типа FinReportServiceTypes. Также их удобно наследовать от общих классов.

По идее, ко всем собственным классам в веб-методах необходимо указывать атрибуты [Serializable] и [XmlType (Namespace = FinReportService.XmlNS)]. Однако в данном случае это не обязательно. Ведь если производится только XML-сериализация, то атрибут [Serializable] не нужен, а XML нэймспейс и так по умолчанию берется из атрибута [WebService]. Отмечу, что в отличие от WCF в ASMX используется обычный XmlSerializer, что позволяет широко управлять сериализацией с помощью таких стандартных атрибутов как [XmlType], [XmlElement], [XmlIgnore] и т.д.

3. Прокси-класс с помощью wsdl.exe Утилита wsdl.exe является соответствующей для asmx техникой потребления SOAP веб-сервисов. По wsdl файлу или ссылке она генерирует прокси-класс — специальной класс, максимально упрощающий обращение к данному веб-сервису. Разумеется, не важно на какой технологии реализован сам веб-сервис, это может быть что угодно — ASMX, WCF, JAX-WS или NuSOAP. Кстати, у WCF аналогичная утилита называется SvcUtil.exe.Утилита расположена в папке C:\Program Files (x86)\Microsoft SDKs\Windows, более того, она там представлена в разных версиях, в зависимости от версии .net, разрядности, версии windows и visual studio.

225d3921c163464bb2e965145991271c.png

Примеры использования

wsdl http://192.168.1.101:8080/SomeDir/SomeService? wsdlwsdl HabraService.wsdl

Давайте сделаем клиента для FinReportWebService. В текущем или новом солюшене создайте новый Windows Forms проект FinReportWebServiceClient. Добавьте в нем папку ProxyClass, скопируйте в нее утилиту wsdl.exe и создайте в ней батник GenProxyClass.bat: wsdl /n: FinReportWebServiceClient.ProxyClass http://localhost:3500/FinReport.asmx? wsdlpause

С помощью аргумента /n: FinReportWebServiceClient.ProxyClass мы указываем нэймспейс для класса. Запустив его, вы должны получить файл FinReportService.cs. Через Solution Explorer — Show All Files, включите все три файла в солюшен.908f7d0765f143d9a7732e6a467fbed2.png

На форме добавьте кнопку, а в исходный код формы следующие три метода:

public static FinReportService GetFinReportService (){    var service = new FinReportService ();     service.Url = «http://localhost:3500/FinReport.asmx»;     service.Timeout = 100×1000;     return service;}  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 и Timeout, причем таймаут указывается в миллисекундах и 100 секунд это его дефолтное значение. Теперь с помощью них вы можете протестировать работу веб-сервиса. Демонстрация работы дальнейших приемов будет показана через вызов метода GetReport и заполнение поля result.Report.Info.В случае создания прокси-класса по wsdl файлу, который ссылается на внешние xsd схемы, все эти схемы необходимо перечислить в команде:

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

Однако кроме ручного создания прокси-класса Visual Studio позволяет его создать автоматически. Пункт «Add Service Reference» позволяет создать прокси-класс по технологии WCF, и там же в «Advanced» есть кнопка «Add Web Reference», которая создает его уже по технологии ASMX.4. Серверный класс по данному wsdl Как известно, wsdl описание веб-сервиса в технологии ASMX генерируется автоматически. Однако иногда возникает обратная задача: по данному wsdl файлу разработать соответствующий ему веб-сервис. Решается она с помощью той же утилиты wsdl.exe. Она может создать необходимый скелет из классов и вам останется только реализовать программную логику веб-методов.Для примера возьмем wsdl нашего веб-сервиса. Сохраните его из браузера как файл FinReport.wsdl либо скопируйте отсюда:

FinReport.wsdl   Фин. отчеты                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          Получение списка ID отчетов по периоду                          Получение отчета по ID                                                                                                                                                                                                                                                                Фин. отчеты                              

Создайте в солюшене новый пустой web-проект с именем FinReportWebServiceByWsdl. В него добавьте папку ServerClass, в которую скопируйте файлы FinReport.wsdl и wsdl.exe. Создайте в ней батник GenServerClass.bat: wsdl /server /n: FinReportWebServiceByWsdl.ServerClass FinReport.wsdlpause

Запустив его, вы должны получить файл FinReportService.cs. Все четыре файла включите в солюшен.e4d1d28648db41df80f1925dfaea5448.png

Итак, как видим, единственное отличие от генерации прокси-класса — это атрибут server. При этом создается абстрактный класс наследованный от WebService с абстрактно описанными веб-методами. Можно от него наследоваться, но при этом все равно придется копировать все атрибуты, поэтому предлагаю сделать следующим образом. Скопировать определение класса в новый файл и пространство имен, убрать слово abstract и написать реализацию методов. После форматирования кода у меня получился следующий файл

using System; using System.Web.Services; using System.Web.Services.Description; using System.Web.Services.Protocols; using FinReportWebServiceByWsdl.ServerClass;  namespace FinReportWebServiceByWsdl {         [WebService (Namespace=«http://asmx.habrahabr.ru/»)]        [WebServiceBinding (Name=«FinReportServiceSoap»,  Namespace=«http://asmx.habrahabr.ru/»)]        public class FinReportService :  WebService {                        [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) {                return new 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) {                return new GetReportResult () {                    Report = new FinReport {                        ReportID = arg.ReportID,                         Date = new DateTime (2015,  03,  15),                         Info = «ByWSDL»                    }                };             }        }}

В этом коде утилита явно описала с помощью атрибутов те параметры веб-сервиса, которые неявно определялись по умолчанию. Остается только добавить файл FinReportByWsdl.asmx, который будет указывать на этот новый класс: <%@ Class="FinReportWebServiceByWsdl.FinReportService" %>

5. ajax ASMX веб-сервис может принимать и возвращать данные в формате JSON, что позволяет реализовать технику ajax. Для работы примера в вашем веб-проекте должны быть следующие три файла: FinReport.asmx — такой же, что и в первых примерах, всего 1 строка

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

FinReportService.cs — код меняется на следующий using System; using System.Text; using System.Web.Script.Serialization; using System.Web.Script.Services; using System.Web.Services; using Newtonsoft.Json;  namespace FinReportWebService{    [ScriptService]    [WebServiceBinding (ConformsTo = WsiProfiles.BasicProfile1_1)]    [WebService (Description = «Фин. отчеты»,  Namespace = «http://asmx.habrahabr.ru/»)]    public class FinReportService :  WebService{         [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);             return text;         }          [ScriptMethod (ResponseFormat = ResponseFormat.Json)]        [WebMethod]        public string Method_3_POST (int id) {            var result = getFinReportResult (id,  «Method_3_POST»);             JavaScriptSerializer js = new JavaScriptSerializer ();             return js.Serialize (result);         }          [ScriptMethod (ResponseFormat = ResponseFormat.Json)]        [WebMethod]        public string Method_4_POST_ComplexArg (string json) {            var arg = JsonConvert.DeserializeObject(json);             var result = getFinReportResult (arg.ReportID,  arg.Token + » Получен.»);             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,  Мой текст»);             string text = JsonConvert.SerializeObject (result);             byte[] data = Encoding.UTF8.GetBytes (text);              Context.Response.Clear ();             Context.Response.ContentType = «application/json;  charset=utf-8»;             Context.Response.AddHeader («content-length»,  data.Length.ToString ());             Context.Response.BinaryWrite (data);             Context.Response.Flush ();         }          private GetReportResult getFinReportResult (int id,  string info) {            return new GetReportResult () {                Report = new FinReport () {                    ReportID = id,                     Info = info,                     Date = new DateTime (2015,  03,  15),                 }            };         }    }      public class FinReport {        public DateTime Date { get;  set;  }        public string Info { get;  set;  }        public int ReportID { get;  set;  }    }     public class GetReportArg {        public int ReportID { get;  set;  }        public string Token { get;  set;  }    }     public class GetReportResult {        public FinReport Report { get;  set;  }    }}

Page.htm — собственно веб-страница                                          Div 1

    Div 2
    Div 3
    Div 4
    Div 5    Div 6    
    Method 1    
    Method 2    
    Method 3    
    Method 4    
    Method 5    
    Method 6 

Также в примере используется библиотека Json.NET aka Newtonsoft.Json.Чтобы веб-сервис мог работать с 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:                                                     

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 и какой-либо первой строкой: fa7c7c830d1f46fabebc3b3cddc6b318.png

Таким образом при компиляции в папке bin будет автоматически создаваться папка MyFiles с указанным файлом, к которому мы будем обращаться. Также этот код демонстрирует обращение к вышестоящей папке FinReportWebService_Files, которая создается автоматически.

Итак, метод getReportInfo возвращает текст, который содержит следующую информацию:

Расположение самого веб-сервисаПуть до вложенного файла Cars.txtПервую строчку этого файлаТекст возможной ошибки его чтения или модификацииПуть до вышестоящей папки FinReportWebService_FilesПуть до успешно созданного в ней файлаТекст возможной ошибки создания папки или файла

После публикации веб-сервиса в IIS, где его учетной записи разрешено только читать файлы мы получим следующий текст с ошибками:

dirRoot = C:\CommonFolder\publish_FinReportfileCars = C:\CommonFolder\publish_FinReport\bin\MyFiles\Cars.txtLine 1 = AudiAccess to the path 'C:\CommonFolder\publish_FinReport\bin\MyFiles\Cars.txt' is denied.dirFiles = C:\CommonFolder\FinReportWebService_FilesAccess 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 на следующее:                        

Здесь мы видим две кастомные настройки и стандартного вида compilation.Обращение к значениям кастомных настроек рекомендуется производить через специальный класс, который будет возвращать их типизированные значения и осуществлять прочую низкоуровневую логику. Вот пример такого класса, добавьте его в проект:

using System; using System.Collections.Generic; using System.Configuration;  namespace FinReportWebService {    internal static class WebConfig {                public static int ReportType { get { return getStructureValue(«ReportType»);  } }        public static string ReportSubject { get { return getTextValue («ReportSubject»);  } }        public static string DbLogin { get { return getTextValue («DbLogin»,  true);  } }        public static st

© Habrahabr.ru