.NET体系结构问题:2 Web服务,如何更改运行时使用的服务?

时间:2020-03-06 14:47:07  来源:igfitidea点击:

我正在使用Reporting Services和Sharepoint,我有一个利用Reporting Services的应用程序,但是客户希望我们的应用程序集成到SharePoint中。当前,我们与ReportService.asmx Web服务紧密结合,该服务公开了执行操作的各种方法。当启用报表服务器时,Reporting Services具有一种称为" Sharepoint集成模式"的功能,并且使用Sharepoint来管理报表。 Sharepoint添加了一个名为ReportService2006.asmx的新Web服务,该服务几乎完全相同。

现在,我们的应用程序使用对ReportService的Web引用,并使用该服务公开的各种对象。 ReportService2006具有完全相同的对象,但它们显然位于不同的名称空间中,例如,我对每个服务有2个Web引用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);
    }
}

所以我有2个实现,每个实现都实例化一个不同的Web服务,例如:

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绑定,并且某些方法会返回来自网络引用的对象,例如CatalogItem。因此,由于我的ReportService2006实现是从其他命名空间引用CatalogItem,因此无法构建项目。

有任何想法吗?我在这方面完全走错了方向吗?

解决方案

我认为我们在这种情况下正朝着正确的方向前进,将它带回家需要花费大量的工作。我将创建一些代理类,这些代理类可以使用反射或者动态方法包装两个版本的类。我还看到人们使用远程命名空间中的代理类在运行时拦截方法调用并将它们定向到正确的位置,这样我们可以按需创建动态方法,而无需手工编码它们,而这正是我们真正需要的是与对象接口匹配的接口。

添加所需的引用,或者为CatalogItem和其余特定类构建包装。我将构建包装器,该接口应该能够独立存在,而无需引用任何特定的实现。

如果Web服务驻留在不同的名称空间中,那么就不会有简单的解决方案(例如,更改URL这样简单的事情)。但是,我们似乎在抽象方面走了正确的路。

但是,如果我们喜欢冒险,可以自己修改生成的Web服务类(" reference.cs"文件),然后将其手动添加到项目中。首先创建一个通用接口,然后修改文件中的第一行,如下所示:

public partial class MyWebService : SoapHttpClientProtocol, IMyWebService

然后,我们可以使用它来调用代码:

IMyWebService webService = new MyWebService();  // Or you can use a Factory

在VS2008中,如果尝试将ServiceReference添加到Web服务,则会看到一个高级按钮。单击它时,有一个"重用类型"选项。

最可靠的解决方案是创建一个CatalogItem接口,并为每个Web服务创建包装,然后将整个工厂隐藏在工厂后面。工厂将包含用于调用"正确的" Web服务的逻辑,并且必须更改客户端代码才能使用该接口,但这是一个更好的改变。

WCF确实通过服务合同解决了大多数此类问题,如果我的早期建议被证明过于难以管理,则可以考虑迁移到WCF解决方案。