views:

853

answers:

4

I'm creating a DLL with a reference to web services (I don't have the choice to do so) but I have to add web service references to the project that uses the DLL for it to work.

Example, I have the DLL called API.DLL that calls a web service called WebService.svc that I want to use in a project called WinForm. First, I have to add a "Service Reference" to WebService.svc in API.DLL. Then, I add a reference API.DLL to WinForm but it doesn't work unless I also add a service reference to WebService.svc in WinForm.

What can I do to avoid that last step?

+1  A: 

Is that because you need the service reference so that the WinForm app can reference the types returned by your service?

If that's the case, you could turn your API dll into a wrapper for the service, and wrap up all the methods available on the service in API, and do the same for the objects (assuming that they are clases you have created). Obviously, you'll have to convert all the objects that the service returns into the objects in the API. But once that's done, you shouldn't need to reference the service in WinForm. (funnily enough, I'm in the middle of doing something similar myself!).

Paul Manzotti
In fact, my API.dll doesn't return any type from the webservice directly to avoid that error. It's like the DLL uses service references from the host project and not from itself.
dan
Well, I'm confused then! What happens if you create a new project and reference your API.dll? Do you get the same error?
Paul Manzotti
Yes, I have this error if I do not add the references to the web service too. I think it's because of all the auto-generated classes don't follow the DLL.
dan
@dan, the generated classes are compiled into the assembly. please see my answer.
Sky Sanders
+5  A: 

You may be using types exposed by the web service, or it may be that you are having to add the web reference so that appropriate connection information is added to the config file. A winform application will not inherit or use a DLL's config file in any way unless you were to cook up some fancy loading mechanism for it. In other words, in the DLL when you add a web reference, it's config file gets information about how to connect to the web service, but when you then use the DLL in an application, your application needs that info in it's own config file, thus you must add a web reference so that the information is generated.

In regards to using a type exposed by the web reference, I'm not sure if this could be an issue you are experiencing. I have encountered this kind of thing in DLLs. For example, SharpMap.dll declares a SharpMapData class, and WrapperOfSharpMap.dll has a method called ProcessData(SharpMapData blah)

If I write a WinForm application and add a reference to WrapperOfSharpMap.dll, I also have to add a reference to SharpMap.dll because to call ProcessData I have to create a SharpMapData instance to pass to the function. In other words, I am using a type declared in SharpMap.dll, therefore need a reference to it.

To resolve this problem, the creator of WrapperOfSharpMap.dll must create a WrapperSharpMapData class like so:

class WrapperSharpMapData
{
  private SharpMapData hiddenSharpMapData;

  //create proprerties to access data elements using standard CLR types or other wrapper types
}
AaronLS
I think the problem is really because I have to reference the web service in the WinForm but I don't want that step. I would like the developer to reference the .DLL and that the web service would be referenced automatically. How can I do that?
dan
@dan, no you do not. Something else is wrong.
Sky Sanders
@dan How would the WinForm get configuration information for connecting to the web service without adding a reference to the web service? Look at what happens to your config file when you add a web reference. Config settings from DLLs don't affect EXEs in any way.
AaronLS
A: 

You could try looking into svcutil.exe , which allows you to generate the client side proxy code for your service via the command line. You should be able to take the code file that it produces and simply add it to your DLL project. This lets you bypass Visual Studio completely.

tbreffni
+3  A: 

Your first step is to prove to yourself that this is possible and then adapt your project.

you can download the runnable solution here.

I just went through the steps and enumerated my actions to produce the results you desire.

    Create a web app project (an thus a solution) named 'ReferencedWebService'
    Add a web service, just leave the default name and implementation
    Add a class library named 'ReferencedWebserviceAPI'
        Add Service Reference
            >Advanced
                >Add Web Reference>Web services in this solution
                    >WebService1
                        >Add reference leaving name as 'localhost'
    Add a console application project named 'ReferencedWebserviceClient'    
    To ReferencedWebserviceClient: 
        Add Reference
            >Projects
                >ReferencedWebserviceAPI
        Add Reference
            >.Net
                >System.Web.Services

    In Program.cs replace Main:

    static void Main(string[] args)
    {
        var svc = new ReferencedWebserviceAPI.localhost.WebService1();
        var result = svc.HelloWorld();
        Console.WriteLine(result);
        Console.ReadLine();
    }


    Set ReferencedWebserviceClient as startup project and run.

    Ok, this is simplest scenario. One issue you will have to deal with is that the default Service URL is hardcoded in the .dll,
    and it is set to a ported address on your dev machine.

    You will want to add a configuration parameter to your client project. The simplest and most portable way is to use an appSetting.

    To ReferencedWebserviceClient:
        Add Item
            >Application Configuration File

    Replace contents of App.Config with this, of course replace the value with the appropriate value on your machine.

    
    
      
        
      
    


        Add Reference
            >.Net
                >System.Configuration

    Now replace Main with this:

    static void Main(string[] args)
    {
        var svc = new ReferencedWebserviceAPI.localhost.WebService1
                      {
                          Url = ConfigurationManager.AppSettings["serviceUrl"]
                      };
        var result = svc.HelloWorld();
        Console.WriteLine(result);
        Console.ReadLine();
    }

This is the baseline for embedding services in a redistributable .dll.

Try to apply this model to your current project and see how that works for you.

If you still have problems, you most definitely have a reference issue and should start looking at it from that perspective.

Hope this helps

Sky Sanders