Архитектурная проблема .NET:2 Веб-службы. Как изменить, какая из них будет использоваться во время выполнения?
-
02-07-2019 - |
Вопрос
Я работаю с Reporting Services и Sharepoint. У меня есть приложение, которое использует службы отчетов, однако клиент хотел бы, чтобы наше приложение было интегрировано в SharePoint.В настоящее время мы тесно связаны с веб-сервисом ReportService.asmx, который предоставляет различные методы выполнения операций.В службах Reporting Services есть так называемый «режим интеграции с SharePoint», когда он включен, сервер отчетов работает по-другому, и для управления отчетами используется Sharepoint.Sharepoint добавляет новую веб-службу ReportService2006.asmx, которая практически аналогична.
Теперь наше приложение использует веб-ссылку на ReportService и различные объекты, предоставляемые этой службой.ReportService2006 имеет точно такие же объекты, но они, очевидно, находятся в другом пространстве имен. Например, у меня есть 2 веб-ссылки - по 1 на каждую службу, поэтому есть объект MyApplication.ReportService.CatalogItem и еще один MyApplication.ReportService2006.CatalogItem.
Я попытался использовать внедрение зависимостей, чтобы отделить Службу от нашего приложения в сочетании с фабричным шаблоном, чтобы определить, какую реализацию моего интерфейса нужно создать.Вот мой интерфейс.Я упростил его, включив в него только те вызовы, которые мне нужны для этого приложения.
using System;
using NetworkUserEncrypt.ReportService;
namespace MyApplication.Service
{
public interface IReportingService
{
CatalogItem CreateDataSource(string DataSource, string Parent, bool Overwrite, DataSourceDefinition Definition, Property[] Properties);
void DeleteItem(string Item);
DataSourceDefinition GetDataSourceContents(string DataSource);
byte[] GetReportDefinition(string Report);
CatalogItem[] ListChildren(string Item);
}
}
Итак, у меня есть две реализации, каждая из которых создает экземпляр другого веб-сервиса, например:
namespace MyApp.Service.Implementation
{
class ReportingServiceImpl : IReportingService
{
ReportingService _service = null;
public ReportingServiceImpl()
{
ReportingService _service = new ReportingService();
}
/* SNIP */
}
}
и
namespace MyApp.Service.Implementation
{
class ReportingService2006Impl : IReportingService
{
ReportingService2006 _service = null;
public ReportingService2006Impl()
{
ReportingService2006 _service = new ReportingService2006();
}
/* SNIP */
}
}
Итак, я планирую внедрить их в свой ServiceWrapper во время выполнения.Однако, если вы заметите, что интерфейс привязан к ReportService, а некоторые методы возвращают объекты из веб-ссылки, например.КаталогЭлемент.Таким образом, мой проект не будет собран, поскольку моя реализация ReportService2006 ссылается на CatalogItem из другого пространства имен.
Есть идеи?Я иду совершенно в неправильном направлении?
Решение
Самое надежное решение — создать интерфейс CatalogItem, создать обертки для каждого из ваших веб-сервисов и спрятать все это за фабрикой.Фабрика будет содержать логику для вызова «правильного» веб-сервиса, и для использования интерфейса придется изменить клиентский код, но это изменение к лучшему.
WCF действительно решает большинство этих проблем с помощью сервисных контрактов, и если мой предыдущий совет окажется слишком невыполнимым, вы можете рассмотреть возможность перехода к решению WCF.
Другие советы
Я думаю, что вы движетесь в правильном направлении в этой ситуации. Просто потребуется гораздо больше работы, чтобы довести ее до конца.Я бы создал несколько прокси-классов, которые могли бы обертывать обе версии классов, используя отражение или динамические методы.Я также видел, как люди использовали прокси-классы из пространства имен удаленного взаимодействия для перехвата вызовов методов во время выполнения и направления их в нужное место. Таким образом, вы могли бы создавать динамические методы по требованию, а не писать их вручную, и все, что вам действительно нужно для этого. — это интерфейс, соответствующий интерфейсу объекта.
Либо добавьте необходимую ссылку, либо создайте оболочки для CatalogItem и остальных конкретных классов.Я бы создал обертки, интерфейс должен быть самостоятельным, не ссылаясь на какую-либо конкретную реализацию.
Если веб-службы находятся в разных пространствах имен, то тривиального решения не существует (например.что-то простое, например изменение URL-адреса).Хотя с абстракцией вы, похоже, на правильном пути.
Однако если вы любите приключения, вы можете самостоятельно изменить сгенерированные классы веб-служб (файлы «reference.cs»), а затем вручную добавить их в свой проект.Сначала создайте общий интерфейс, затем измените первые строки файла следующим образом:
public partial class MyWebService : SoapHttpClientProtocol, IMyWebService
Затем вы используете это для вызова кода:
IMyWebService webService = new MyWebService(); // Or you can use a Factory
В VS2008, если я попытаюсь добавить ServiceReference к веб-сервису, я увижу кнопку «Дополнительно».При нажатии на нее появляется возможность «повторно использовать типы».