views:

411

answers:

5

I am working with Reporting Services and Sharepoint, I have an application that leverages reporting services however a client would like our application integrated into sharepoint. Currently we are tightly coupled to the ReportService.asmx webservice which exposes various methods for performing operations. Reporting Services has something called "Sharepoint Integration mode" when enabled the report server works differently and Sharepoint is used to manage the reports. Sharepoint adds a new web service called ReportService2006.asmx which is almost exactly the same.

Now our application uses a web reference to the ReportService and uses various objects exposed by the service. ReportService2006 has exactly the same objects but they are obviously in a different namespace e.g I have 2 web references - 1 to each service so there is an object MyApplication.ReportService.CatalogItem and another MyApplication.ReportService2006.CatalogItem.

I've tried to use dependency injection to absract the Service out of our application coupled with a factory pattern to determine which implementation of my interface to instantiate. Heres my interface. I've simplified it to include only the calls I need for this application.

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);
    }
}

So I have 2 implementations of this each instantiating a different web service e.g:

namespace MyApp.Service.Implementation
{
    class ReportingServiceImpl : IReportingService
    {
        ReportingService _service = null;

        public ReportingServiceImpl()
        {
            ReportingService _service = new ReportingService();
        }

        /* SNIP */
    }
  }

and

namespace MyApp.Service.Implementation
{
    class ReportingService2006Impl : IReportingService
    {
        ReportingService2006 _service = null;

        public ReportingService2006Impl()
        {
            ReportingService2006 _service = new ReportingService2006();
        }

        /* SNIP */
    }
  }

So the plan is I can inject these into my ServiceWrapper at run time. However - if you'll notice the interface is tied to the ReportService and some of the methods return objects that are from the web reference e.g. CatalogItem. Thus my project won't build because my implementation for ReportService2006 is referencing the CatalogItem from a different namespace.

Any ideas? Am I going totally the wrong direction with this?

+1  A: 

I think you are headed in the right direction for this situation, It's just going to take a fair amount more of work to drive it home. I would create some proxy classes that can wrap both versions of the classes using reflection or dynamic methods. I've also seen people use the proxy classes from the remoting namespace to intercept method calls at runtime and direct them to the right place, that way you could create the dynamic methods on demand instead of hand coding them, all you really need for that is an interface that matches the object's interface.

scmccart
+1  A: 

Either add the reference it needs or build wrappers for CatalogItem and the rest of the specific classes. I'd build the wrappers, the interface should be able to stand on its own without referencing any particular implementation.

Mauricio Scheffer
+1  A: 

If the Web Services reside in different namespaces, then there is no trivial solution (eg. something as simple as changing the URL). You seem to be on the right track with abstraction though.

If you're feeling adventurous though, you can modify the generated Web Service classes yourself (the "reference.cs" files), and then manually add them to your project. First create a common Interface, then modify the first lines in the file like such:

public partial class MyWebService : SoapHttpClientProtocol, IMyWebService

Then you use this to call the code:

IMyWebService webService = new MyWebService();  // Or you can use a Factory
ilitirit
+1  A: 

In VS2008, if I try to add a ServiceReference to a webservice, I see an advanced button. When clicking it, there is an option to "re-use types".

David B
+1  A: 

The most robust solution is to create a CatalogItem interface and create wrappers for each of your web services and hide the whole thing behind a factory. The factory will contain the logic for calling the "correct" web service and the client code will have to be changed to use the interface but it is a change for the better.

WCF does solve most of these issues with Service Contracts and if my earlier advice proves to be too unmanageable you could consider migrating towards to a WCF solution.

Phil Bennett