Using a Service Reference in VB.NET - vb.net

i have added a service ref in my VB.NET application.
i can see the objects in the object browser. i need to log in first to obtain a session ID.
when I try
dim client as new serviceReference1.IGPSBulkData
I get an error
'New cannot be used on an interface'.
IGPSBulkdata is the only option that includes the login function so Im not sure how to make this call
any ideas?

When you add a service reference several classes are being generated from the service' WSDL. Take a closer look at the generated code 🤓 There will be something like GPSBulkDataClient.
This generated client class can be used to communicate with the service.

The error is correct; you cannot instantiate an Interface.
If you open Object Browser in Visual Studio and search for IGPSBulkData you should be presented with a list of classes which implement it. From there you can instantiate your client object (if that's what you need to do with that class).
So if there was a class called GPSBulkDataThing which implements IGPSBulkData your code might resemble:
Dim client as serviceReference1.IGPSBulkData = new GPSBulkDataThing(maybe with some arguments here)

Related

Service Reference not reusing data types client side

This question has been asked many times but I can't find a solution.
I have a WCF service with a function that takes in a customer object. This customer object is in a separate project that both the client and server code reference. When I add the service reference to the client project, I choose the option to reuse data types. However, when I try to call the function on the client side and pass the customer object in, I get this error:
Error 39 Value of type 'Real.Namespace.Customer' cannot be converted to 'Service.Namespace.Customer'.
The "Real.Namespace" is the class it should be using. "Service.Namespace" is the auto generated class created by the service reference. I know this is supposed to work, so there must be some reason why it is unable to find the real class and reuse it.
I've tried this with very simple objects and it still won't work. Any ideas on why the auto generated code can't find the real class and use it?
Edit: I've tried using a very simple object just to see if I could get it to work. So right now I'm just using a test class that looks like this:
Namespace DTO
<DataContract>
Public Class Test
<DataMember>
Public Property Name As String
End Class
End Namespace

Type being passed through web service not being recognized by consuming code

I am creating an XML web service that passes an array of custom types. In my consuming code I am referencing the code as a web reference which I have given the namespace MYWS. Now in code I am trying to assign the results of my web service call to an array of my type like so :
'instance to make a call to my web service
Dim srv As New MYDWS.ServiceNameWSSoapClient
'array to hold the results
Dim arr() As MyClass
'assign the web service call results
arr = srv.myWebMethod()
When I do this the complier complains, saying:
Value of 1 dimensional array of my.namespace.MyClass cannot be
converted to 1 dimensional array of my.namespace.MYWS.MyClass because
my.namespace.MYSW.MyClass is not derived from my.namespace.MyClass
Now I understand the message, the thing is they are the same class. The class is declared in my calling code by the web service references a dll from that project. How do I tell the compiler that these are the same type? Any help would be very much appreciated. Thanks!
The upshot is that you have a namespace mismatch. If you right-click on MyClass in your example and select Go To Definition, where does it take you? I suspect that you may end up in a locally defined class.
The solution is to change
Dim arr() As MyClass
to
Dim arr() As MYWS.MyClass
Update based on information in comments
The problem with using the web service is that you cannot cast it to a local class.
You have a couple of options depending on exactly what you need out of the local class.
If you only need methods to act on the data in the class or you need additional properties, you can create a partial class in your environment that extends the class created by the web service. For example:
Namespace MYWS
Public Partial Class MyClass
Public Property SomeAdditionalData As String
Public Sub SomeMethod
' Perform some operations on the class members
End Sub
End Class
End Namespace
However, if you have calculations or other work embedded in the class, then you will need to get the data using the web service class, then copy the data from that class into your local class. If the properties have the same names, you could ease this task using reflection.
As another option, if you have control over the web service, you could change it to a WCF service. This will allow you to reuse the exact same class code on both ends of the communication pipe.
Found a solution to the problem. In the web.config I found this:
<add key="net.mydom.mydom" value="http://localhost:7452/dir/mysvc.asmx"/>
which was what the system automatically entered when I registered the web service. I got the error messages on screen, but everything compiled and ran w/o problem.
When I manually changed to this:
<add key="net.mydom" value="http://localhost:7452/dir/mysvc.asmx"/>
The error messages went away and everything continued to function as expected.
(That only took my 7 years to figure out...)
UPDATE:
Well, not quite the fix, but it must be close. After awhile, the problem came back, when I switched back to to:
<add key="net.mydom.mydom" value="http://localhost:7452/dir/mysvc.asmx"/>
it went away again...sure to come back at any time...
UPDATE
If I explicitly add:
imports net.mydom
to the top of my code, the message goes away again (even though I was explicitly using the full net.mydom. when typing the variables.

How to Allow Client-Service to Build Complex Object in WCF Service?

I made a simple PasteBin demo example of what my code looks like: http://pastebin.com/GpDhPRVm
My actual Process object is extremely complex that includes adding collections of Tasks, Documents, Workflows, etc into a Process object and setting properties through methods, etc.
My PasteBin example is as simple as I can make it to show where things break down. Including the Process object in the CreateNewProcess method in my service (shown in code below), allows the service user to automatically "see" the Process object, properties and enumerators in their instance on the client side.
<ServiceContract()>
Public Interface ICreateProcess
<OperationContract()>
Sub CreateNewProcess(ByVal newprocess As Process)
End Interface
However, it does not allow them to use any of the methods like the 'AddTask' method (shown in PasteBin example) and it also doesn't expose the Task or TaskCollection objects. Even if I decorate the methods with DataContract, OperationContract, etc they still are not visible to the client service.
This is my major issue: I need the client service to be able to fully "build" the Process object and then pass it in to the CreateNewProcess method.
Another small note: (to avoid comments asking me about it) is that I made sure that all of my properties are simple types that are interoperable since this needs to be able to work for Java - not just .NET clients.
Ok, I figured it out with a little help from a buddy of mine.
Can't use methods at all outside the .svc service class; only properties, enums and sub objects will translate down to the client. (I figured this)
Then, instead of using a Collection, you have to use a generic List type.
So, instead of this:
Public Tasks As New TaskCollection() 'where TaskCollection inherits from Collection
I needed to do this:
Public Tasks As List(Of Task)
And the client will just have to build their own array of Tasks and assign it to the t.Tasks property.
This works like a charm now: http://pastebin.com/rt8HwsXY

Ninject not creating a new instance with constructor arguments in WCF

Here is the scenario. I have a WCF service, when this service is called it passes control to an instance of another class (created via Ninject). In that class I need to do some work, specifically with Entity Framework and repositories. To cut a long story short, I have the following binding declared.
Bind<IGenericProductRepository>()
.To<GenericProductRepository>()
.WithConstructorArgument( "context", new StagingDataContext());
When I want to use this repository I have the following.
using (var genericProductRepository = IoC.Resolve<IGenericProductRepository>())
The problem is, that I only get a new instance of genericProductRepository if it's a brand new request, if the method is called multiple times in the same request I get an error stating that the context (the EF context) is already disposed, this is because it seems like I am getting the same instance back that was already disposed in the using statement. To explain it another way, using the Microsoft WCF Test Client, if I invoke it the first time, the code runs fine, if I push the invoke button again (without restarting the test client, i.e. the same request) then it throws this error about it being disposed already.
I have tried to play around with the various "scopes" that come with Ninject, but clearly I am missing something.
So my basic question is, how do I get a new repository whenever it hits that line, instead of using the same one ? Help would be greatly appreciated, I'm really trying to push for my company to adopt Ninject and drop Spring.
Look at your binding again. Even without any knowledge about Ninject you should notice that the instance of your context is created exactly once at the time the binding is defined. But what you want is have a new context on every resolve. Best it is done by not using WithConstructorArgument and let Ninject create the instance. Therefore you have to define a additional binding for the type of context. If this is not possible for some reason you have to use the lazy version of WithConstructorArgument
WithConstructorArgument("context", ctx => new StagingDataContext())
Furthermore, you might want to try The WCF extension for Ninject:
https://github.com/ninject/ninject.extensions.wcf
That way you can get rid of the ServiceLocator like usage.

.NET webservice using an instance of a parameter type?

I have a Windows forms project and a Web Service project in my solution, and I'm trying to call the web service and return a customer object as the result. The problem is that when I try to receive the return object, I get an error that it can't convert it. For example, here is the signature for my webservice:
Public Function GetDriverByID(ByVal DriverID As Integer) As Driver
And here is the code I'm using to call it:
Dim d As Driver = mywebserviceinstance.GetDriverByID(1)
But I receive this compile-time error (wsDrivers is the name of the web reference I've added to my form project): "Value of type ProjectNamespace.Common.wsDrivers.Driver cannot be converted to ProjectNamespace.Common.Driver"
This "Common" namespace contains the Driver class, and I'm not sure why the return class from the web service isn't just a generic "Driver", but is instead a "wsDrivers.Driver", and I can't convert it back. Anybody know how I can deal with this type mismatch?
EDIT: Thanks for the explanations - this actually makes it clear what it's doing. However, is there any way that I can force it to use the actual type instead of the proxy (or, rather, is there any way to convert between the "real" instance and the "proxy" instance), or do I have to serialize the properties before I send them over the wire, and then manually de-serialize the return values?
This is actually pretty common. What's happening is that the Web Service has defined in it the definitions of all the types used in the web service. When you add a reference to that web service, it auto-generates a proxy type in a sub namespace of your namespace. That is what is being returned by your web service when you call it.
However, you probably are also referencing the same library that the web service does seperately that contains the same type. That is the type that is expected when you Dim Driver. That's why there is a mismatch.
The web service reference in a VB.NET or C# project can reference any type of web service and is not limited to those provided by ASP.NET. That is why Visual Studio creates proxy classes for each object which can be retrieved from the web service.