Мы рассмотрели стандартные файлы Web-сервиса, создаваемые в Visual Studio при помощи шаблона Web-сервиса. Теперь вы готовы исследовать разработку реального Web-сервиса при помощи Visual Studio 2008. Для примера мы будем разрабатывать Web-сервис CustomerProfile. Этот Web-сервис будет обеспечивать методы для получения информации о клиентах из хранилища данных и для сохранения изменений этой информации. Попутно мы рассмотрим более тонкие моменты разработки Web-сервиса .NET. Вот основные шаги этого процесса:
1. Для создания Web-сервиса добавьте в шаблон ASP.NET Web Service Application новый Web-сервис. Назовите его CustomerProfile.asmx.
2. Удалите метод HelloWorld и вместо него создайте методы с названиями GetCustomer- Profile, SaveCustomer и DeleteCustomer. Каждый метод должен быть помечен атрибутом [WebMethod].
3. Добавьте в ваше решение новый проект библиотеки классов. Назовите этот проект BusinessEntities. Данный проект будет содержать фактическое описание простого класса Customer с набором свойств. В листинге 19.1 показан пример этого кода.
using System;
namespace BusinessEntities {
public class Customer {
public string Id { get; set; } public string Name { get; set; } public string Email { get; set; } public string AddressLinel { get; set; } public string AddressLine2 { get; set; } public string City { get; set; } public string State { get; set; } public string PostalCode { get; set; } public string Phone { get; set; } public bool ContactEmail { get; set; } public bool ContactPhone { get; set; }
}
4. Затем создайте второй проект библиотеки классов с названием Entity Services и добавьте в эту библиотеку класс CustomerProfile. Пространство имен EntityServices обеспечит фактическую реализацию кода, который выполняется от имени Web-метода SaveCustomer данного сервиса. Фактически сервис является прокси для метода EntityServices . CustomerProfile. SaveCustomer. Этот метод выполняет работу по сохранению данных о клиенте.
Реализация при помощи прокси не обязательна. Вы можете определить всю логику выполнения прямо внутри Web-сервиса. Однако мы показываем именно такой пример по двум причинам. Первая состоит в том, что большинство приложений использует уже существующий код. Поэтому может быть весьма полезным создание прокси для предоставления этого существующего кода через Web-сервисы. Вторая состоит в том, что это пример хорошего дизайна. Наличие кода реализации в отдельном объекте позволяет использовать его многократно, облегчает модульное тестирование и позволяет применять более традиционные клиентские конфигурации (и не использовать Web-сервисы).
5. Создайте базу данных, в которую будет считываться и сохраняться информация по профилю клиента. Это почти не имеет отношения к Web-сервису, но поможет придать за
конченность нашему примеру. Таблица клиентов— это все, что нам потребуется. На рис. 19.6 показан пример таблицы клиентов, добавленной в файл базы данных Customer.mdf проекта EntityServices.
Рис. 19.6. Таблица базы данных по клиентам
6. Теперь вы можете писать методы для получения, сохранения и удаления клиента. Сначала добавьте ссылку в проекте EntityServices на проект BusinessEntities. Затем добавьте методы SaveCustomer, GetCustomer и DeleteCustomer в класс CustomerProfile созданного вами проекта библиотеки классов EntityServices. В листинге 19.2 показан простой код, который работает с только что созданной вами таблицей базы данных.
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Data;
using System.Text;
using BusinessEntities;
namespace EntityServices {
public class CustomerProfile { string _dbConnect =
0"Data Source=.\SQLEXPRESS;At'tachDbFilename=C:\...\Customer.mdf;
Integrated Security=True;User Instance=True";
\
public Customer GetCustomer(string customerld) {
StringBuilder sql = new StringBuilder("SELECT id, name, email, ") ; sql.Append("addressLinel, addressLine2, city, state, postalCode,"); sql.Append("phone, contactPhone, contactEmail "); sql.Append("FROM customer WHERE id = @id");
using (SqlConnection cnn = new SqlConnection(_dbConnect)) {
SqlCommand cmd = new SqlCommand(sql.ToString(), cnn); cmd.CommandType = CommandType.Text;
cmd.Parameters.Add(new SqlParameter("id", customerld)); cnn.Open();
SqlDataReader dr = cmd.ExecuteReader(); dr.Read();
Customer с = new Customer();
с.AddressLinel = dr["addressLinel"].ToString();
c.AddressLine2 = dr["addressLine2"].ToString();
c.City = dr["city"].ToString();
c.ContactEmail = (bool)dr["contactPhone"];
с.ContactPhone = (bool)dr["contactEmail"];
c.Email = dr["email"].ToString();
c.Id = dr["id"]-ToString() ;
c.Name = dr["name"].ToString();
c.Phone = dr["phone"].ToString();
c.PostalCode = dr["postalCode"].ToString() ;
c.State = dr["state"].ToString();
return c;
}
}
public void SaveCustomer(Customer customer) {
StringBuilder sql = new StringBuilder();
SqlCommand cmd = new SqlCommand();
// Определить: обновить или сохранить if (customer.Id == null) {
// Предположим вставку
sql.Append("INSERT INTO customer (id, name, email, addressLinel, ") ; sql.Append("addressLine2, city, state, postalCode, phone, ");
sql.Append("contactPhone, contactEmail) ") ;
sql.Append("VALUES(@id, @name, @email, @addressLinel, ");
sql.Append("0addressLine2, @city, ©state, @postalCode, @phone, ");
sql.Append("0contactPhone, 0contactEmail)");
cmd.Parameters.Add(new SqlParameter("@id",
Guid.NewGuid().ToString()));
} else {
// Предположим обновление
sql.Append("UPDATE customer set name=@name, email=@email, ") ;
sql.Append("addressLinel=@addressLinel, ");
sql.Append(MaddressLine2=@addressLine2, city=@city, ");
sql.Append("state=@state, postalCode=@postalCode, ") ;
sql.Append("phone=@phone, contactPhone=@contactPhone, ");
sql.Append("contactEmai1=0contactEmail ");
sql.Append("WHERE id=@id ");
cmd.Parameters.Add(new SqlParameter("©id", customer.Id));
}
// Добавить дополнительные параметры
cmd.Parameters.Add(new SqlParameter("@name", customer.Name)); cmd.Parameters.Add(new SqlParameter("0email", customer.Email)); cmd.Parameters.Add(new SqlParameter("©addressLinel",
' customer.AddressLinel));
cmd.Parameters.Add(new SqlParameter("0addressLine2",
customer.AddressLine2)); cmd.Parameters.Add(new SqlParameter("0city", customer.City)); cmd.Parameters.Add(new SqlParameter("@state", customer.State)); cmd.Parameters.Add(new SqlParameter("0postalCode",
customer.PostalCode)); cmd.Parameters.Add(new SqlParameter("0phone", customer.Phone)); cmd.Parameters.Add(new SqlParameter("©contactPhone",
customer.ContactPhone)); cmd.Parameters.Add(new SqlParameter("©contactEmail",
customer.ContactEmail));
using (SqlConnection cnn = new SqlConnection(_dbConnect)) { cmd.CommandType = CommandType.Text; cmd.CommandText = sql.ToString(); cmd.Connection=cnn; cnn.Open();
cmd.ExecuteNonQuery();
}
}
public void DeleteCustomer(string customerld) {
string sql = "delete from customer where id = 0id";
using (SqlConnection cnn = new SqlConnection(_dbConnect)) {
SqlCommand cmd = new SqlCommand(sql, cnn); cmd. CommandType = CommandType.Text;
cmd.Parameters.Add(new SqlParameter("©id", customerld)); cnn.Open();
cmd.ExecuteNonQuery();
}
)
}
}
7. Класс EntityServices служит как прокси для Web-сервиса. Теперь вы можете добавить ссылку в проекте Web-сервиса на проекты BusinessEntities и EntityServices.
8. Последний шаг— написать код для самого Web-сервиса. Здесь будет метод GetCustomerProfile, который принимает параметр customerld и возвращает экземпляр Customer. Создайте также метод SaveCustomer, который принимает экземпляр класса Customer, но не возвращает значения. И наконец, создайте метод DeleteCustomer, который принимает customerld. В листинге 19.3 показан код сервиса.
using System;
using System.Collections;
us ing S уs tem.ComponentMode1;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System. Xml. Linq;
using BusinessEntities;
namespace CustomerProfile {
[WebService(Namespace = "
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfilel_l)]
[Toolboxltem(false)]
public class CustomerProfile : System.Web.Services.WebService {
[WebMethod(Description = "Used to return a customer's profile.")] public Customer GetCustomerProfile(string customerld) {
EntityServices.CustomerProfile custProfile =
new EntityServices.CustomerProfile();
return custProfile.GetCustomer(customerld);
}
[WebMethod(Description = "Saves a customer")]
public void SaveCustomer(BusinessEntities.Customer customer) {
EntityServices.CustomerProfile custProfile =
new EntityServices.CustomerProfile();
custProfile.SaveCustomer(customer);
}
[WebMethod(Description = "Deletes a customer")]
public void DeleteCustomer(string customerld) { '
EntityServices.CustomerProfile custProfile = new
EntityServices.CustomerProfile(); custProfile.DeleteCustomer(customerld);
}
}
}
Совет
Когда вы создаете \Л/еЬ-сервис, то лучше всего группировать функциональность в крупноблочные интерфейсы. Нам не нужны такие \Л/еЬ-методы, которые перед вызовом метода выполняют множество мелких операций (таких как настройка свойств). Такая болтливость при обмене через Интернет может быть весьма дорогим удовольствием.
Конечно, такой подход противоречит также и дизайну большинства объектно- ориентированных приложений. Поэтому использование прокси-объекта с целью группировки операций для бизнес-объекта является идеальным. Бизнес-объект можно сериализовать и передать по проводам. На другой стороне он может быть десериализован, после чего с ним можно будет работать (внутри процесса, когда многочисленные вызовы уже не будут дорогим удовольствием).
Теперь, когда вы создали простой Web-сервис, давайте взглянем на то, что определяет этот класс как Web-сервис. Мы скоро вернемся к этому примеру сервиса.