Declare generic Service Reference client object for scoping issue - c#

I have this in my web.config
If this value is live, then I want to call the live web service, and if it's not, then I want to call the test web service.
In my code I want to do something like this:
if (System.Configuration.ConfigurationManager.AppSettings["runMode"] == "live")
{
var client = new CallStatusAvailability.ServiceReference1
.StatusAvailabilityRoomsClient();
}
else
{
var client = new CallStatusAvailability.StatusAvailabilityRooms
.StatusAvailabilityRoomsClient();
}
using (client)
{
...... lots of logic
}
The problem is that client is out of scope. I would like to be able to declare client before the if statement, but not sure what I can define it as?
I could put the using statement within the if or the else statement, but I would then have to duplicate all the logic in both.
At first I tried to create a function that could be called from the if and the else, and pass in client, but then I face the same issue of what type to declare the input client variable as, as an input to the function.

I would suggest that you not add both service references to your project, but a single service reference (probably to the test service) and vary the connection parameters using configuration transforms. You would do this by setting your base web.config up to connect to the test service, then add a transform in web.Release.config to change the binding when deployed using the Release target. This will simplify your logic to the point where you won't need the if-else construct and allow you to create the client within a using statement.

Your issue is that var is declaring a variable. If you need to use a variable in this way you can't use var as it need to be declared at a higher level of scope. Just move your declaration to the containing block. This assumes the service references are using the same type; if not, you need to fix that first or use dynamic if they are semantically identical. You also can't use a using in this context and must use try catch finally.
To use the same types I would suggest generating the proxy using the channel factory or using svcutil so that your types are the same for the different service references.
CallStatusAvailability.ServiceReference1.StatusAvailabilityRoomsClient client = null;
try
{
if (System.Configuration.ConfigurationManager.AppSettings["runMode"] == "live")
{
client = new CallStatusAvailability.ServiceReference1.StatusAvailabilityRoomsClient();
}
else
{
client = new CallStatusAvailability.StatusAvailabilityRooms.StatusAvailabilityRoomsClient();
}
}
catch(..){}
finally
{
client.Dispose();
}

Related

Type Compatibility Between 2 Projects using same WSDL

I have the following
ProjectA - has a helper method I'm creating to accept a wsdl generated type (.csproj is based on .NET 2.0 becaue it has to be for our legacy code)
ProjectAIntegrationTests (.csproj is based on .NET 4.5)
I've added a service reference to our WCF service to both projects in order to use it since I want to create a helper method in projectA that my Integration tests will test. I intend to send in a
Example:
ProjectA - contains a helper method to allow me to send in a request and get a response
the type I send in is a proxy instance of the type or at least that's my intention in how to do this.
using OurCompany.SomeAppName1.Payment.Integration.Tests.PaymentService
namespace EventInventory.TicketPoint.Payment
{
public static class HttpClientHelper
{
public static PreAuthorizeResponse SendHttpRequest(PreAuthorizeRequest authorizationRequest)
{
PreAuthorizeResponse response;
var service = new PaymentService.PaymentService();
response = service.PreAuthorize(authorizationRequest);
return response;
}
}
}
ProjectAIntegrationTests - Related Integration Test from
using System;
using OurCompany.SomeAppName1.Payment.PaymentService;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace OurCompany.SomeAppName1.Payment.Integration.Tests
{
[TestClass]
public class HttpClientHelperTests
{
...
[TestMethod]
public void SendRequest_PreAuthorizatoinWithMinimumValues_ReturnsAuthorizationRespones()
{
// Arrange
PaymentsClient serviceClient = new PaymentsClient(); // proxy client from wsdl
... more code
var preAuthorizeRequest = CreatePreAuthorizeRequest(transactionData, _merchantReference, _securityToken);
// Act
PreAuthorizeResponse preAuthorizeResponse = HttpClientHelper.SendHttpRequest(preAuthorizeRequest);
// Assert
}
The error I get is it's not recognizing the PreAuthorizationRequest instance I'm sending into HttpClientHelper.SendHttpReques() saying the following: "OurCompany.SomeAppName1.Payment.Integration.Tests.PaymentService.PreAuthorizationRequest is not assignable to OurCompany.SomeAppName1.Payment.PaymentService.PreAuthorizationRequest"
so the types are incompatible.
OurCompany.SomeAppName1.Payment.Integration.Tests.PaymentService.PreAuthorizationRequest is not a OurCompany.SomeAppName1.Payment.PaymentService.PreAuthorizationRequest according to .NET
Notice the only thing I can figure different here are the namespaces behind the service. I don't know if that matters but feels like it may be the problem, not sure. If that's true then you can't share client proxy types across projects? Each project is gonna have their own namespace that's specific to that project. My second projet has Integration.Tests in the namespace.
maybe this is a cross boundary thing also that plays into effect?
Try to see your proxy classes as totally different classes. Even if two classes have the same name and are identical (because they were generated from the same wsdl), it doesn't mean you can use an object of type namespace1.ServiceClient where a namespace2.ServiceClient is needed.
Normally, once you add a reference of ProjectA to ProjectAIntegrationTests, you will be able to use the service reference generated code in ProjectAIntegrationTests too. You don't need to add a new service reference on ProjectAIntegrationTests project.
You will also need to add an App.Config on ProjectAIntegrationTests and add there the configuration that you need to access the service (you can copy the necessary configuration from ProjectA).

How to choose a WCF service to connect to?

I have two separate servers with identical WCF services (let's say, WS1 and WS2) and a C# Mobile CF 2.0 project that need to access both of the services.
Can I do something like this on the C# CF2.0 project?
(...)
if (someCondition == true)
{
WS1 aux = new WS1();
}
else
{
WS2 aux = new WS2();
}
aux.service(parameter1);
(...)
note that I want to have the same variable name, independent of which server I'll access. The problem is: I don't know how to declare it outside the conditional statements and when I just declare it inside the conditional statements they're declared as local variables and I don't know how to make the variable public or global.
Any thoughts or help, please?
Since the WCF Service is exactly the same, just running on different servers, then from your client project simply add a service reference to one of them (WS1 for example). This will generate the client proxy for you. Perhaps give it a generic name too, like "serviceX" (replacing X with something appropriate for your application).
Then, in your client config file, copy the client endpoint it created and add another endpoint with the only difference being the address and the endpoint name. Maybe you want to set the endpoint name property on each endpoint to be "WS1" and "WS2" respectively.
Then, in your code, you should be able to do something like this:
(...)
serviceXClient aux = null;
if (someCondition == true)
{
aux = new serviceXClient("WS1");
}
else
{
aux = new serviceXClient("WS2");
}
aux.service(parameter1);
(...)
If you're using .Net 4.0 or higher you could use dynamic typing.
http://msdn.microsoft.com/en-us/library/dd264736.aspx

Reporting Services Web Service, C# .NET code reuse

I'm building a custom front-end for a collection of reporting services servers. I'm adding the ReportingServices2005 web reference to my project using;
http://server/ReportServer_InstanceName/ReportService2005.asmx?wsdl
At the moment my approach is to add this reference for each server, however I'm then struggling with the code reuse aspect. The reporting services classes are then different namespaces.
I'd like to have a method as below;
public string ListReports(Server1WebService.ReportingService2005 service) {
service.Credentials = System.Net.CredentialCache.DefaultCredentials;
service.Server1WebService.CatalogItem[] children = service.ListChildren("/", true);
string list = String.Empty;
foreach (Server1WebService.CatalogItem i in children) {
if (!i.Hidden)
list += i.Name + "</br>";
}
return list;
}
To make this method reusable I need to know how to refactor this so that any instance of the ReportingService2005 class can be passed regardless of the namespace. At the moment I have to specify Server1WebService for all references to ReportingService2005 and CatalogItem.
Provided that all of the SSRS instances are the same version, You should be able to set the URL property on the proxy object:
Server1WebService server.url = new uri ("http://server/ReportServer_InstanceName/ReportService2005.asmx?wsdl"));
If you have multiple versions to deal with, you may need to provide some type of factory object that can correctly instantiate the correct version.
Hope this helps

dynamic binding of web service URI

I have a list of servers, all exposing the same web service interface, that I need to call from my code.
i.e.
https://server1/service.asmx
https://server2/service.asmx
https://server3/service.asmx
My code needs to get this list of servers and invoke the same function on all of them.
I added a web references to this service, and I use "Dynamic" URL behavior. This is supposed to let me create an instance of the server proxy object, set the URI property at runtime, and then invoke the web methods, right?
But it seems the code generated by VS assumes the URI will come from the application's config file, which isn't the case for this app.
public SharpEyeWebService() {
this.Url = global::Company.DotNet.MyProject.Properties.Settings.Default.MyWebService;
if ((this.IsLocalFileSystemWebService(this.Url) == true)) {
this.UseDefaultCredentials = true;
this.useDefaultCredentialsSetExplicitly = false;
}
else {
this.useDefaultCredentialsSetExplicitly = true;
}
}
Is it safe to ignore the default URL the constructor uses and employ the approach I described above?
You can always set the Url, so yes this is safe. The "dynamic" you describe only influences the default Url: whether it hard-coded or comes from config.
So indeed, this is moot if you are supplying this yourself.
The awkward bit here is that it also sets UseDefaultCredentials based on what it finds - so it would be worth setting this manually so you know the value.

Unable to cast object of type MyObject to type MyObject

I have this scenario where a webservice method I'm consuming in C# returns a Business object, when calling the webservice method with the following code I get the exception "Unable to cast object of type ContactInfo to type ContactInfo" in the reference.cs class of the web reference
Code:
ContactInfo contactInfo = new ContactInfo();
Contact contact = new Contact();
contactInfo = contact.Load(this.ContactID.Value);
Any help would be much appreciated.
This is because one of the ContactInfo objects is a web service proxy, and is in a different namespace.
It's a known problem with asmx-style web services. In the past I've implemented automatic shallow-copy to work around it (here's how, although if I were doing it again I'd probably look at AutoMapper instead).
For example, if you have an assembly with the following class:
MyProject.ContactInfo
and you return an instance of it from a web method:
public class DoSomethingService : System.Web.Services.WebService
{
public MyProject.ContactInfo GetContactInfo(int id)
{
// Code here...
}
}
Then when you add the web reference to your client project, you actually get this:
MyClientProject.DoSomethingService.ContactInfo
This means that if, in your client application, you call the web service to get a ContactInfo, you have this situation:
namespace MyClientProject
{
public class MyClientClass
{
public void AskWebServiceForContactInfo()
{
using (var service = new DoSomethingService())
{
MyClientProject.DoSomethingService.ContactInfo contactInfo = service.GetContactInfo(1);
// ERROR: You can't cast this:
MyProject.ContactInfo localContactInfo = contactInfo;
}
}
}
}
It's on that last line that I use my ShallowCopy class:
namespace MyClientProject
{
public class MyClientClass
{
public void AskWebServiceForContactInfo()
{
using (var service = new DoSomethingService())
{
MyClientProject.DoSomethingService.ContactInfo contactInfo = service.GetContactInfo(1);
// We actually get a new object here, of the correct namespace
MyProject.ContactInfo localContactInfo = ShallowCopy.Copy<MyClientProject.DoSomethingService.ContactInfo, MyProject.ContactInfo>(contactInfo);
}
}
}
}
NOTE
This only works because the proxy class and the "real" class have exactly the same properties (one is generated from the other by Visual Studio).
As several of the other answers have suggested, it is because .NET sees them as two different classes. I personally would recommend using something like AutoMapper. I've been using it, and it seems pretty awesome. You can copy your objects in 1-2 lines of code.
Mapper.CreateMap<SourceClass, DestinationClass>();
destinationInstance = Mapper.Map<SourceClass, DestinationClass>(sourceInstance);
Actually this is not a bug. It's a problem with the version changes of your own project!
Because your final run don't use the original imported references on compile!
For example, I was making a chat server, client. I used a packet structure to transmit data on client project.
Then imported the same reference to server project.
When casting Packet packet = (Packet)binaryFormatter.Deserialize(stream); I got the same error. Because the actual running reference at server project is not the reference now at client project! Because I have rebuilt client project many times after!
In casting <new object>=(<new object>) <old object> always the new object needs to be a newer or same version as the old object!
So what I did was I built a separate project to create a DLL for the Packet class and imported the DLL file to both projects.
If I did any change to Packet class, I have to import the reference to both client and server again.
Then the casting won't give the above exception!
How are you referencing the class in your web service project as well as consumer project? If you have simply used a file link, this could well explain the cause of the error. The way serialiasation works for .NET (Web Services or otherwise I believe) is by using reflection to load/dump the data of an object. If the files are simply linked, then they are actually getting compiled to different types in different assemblies, which would explain why you have the same name but can't cast between them. I recommend creating a 'Core' library which both the web service and consumer project references, and contains the ContactInfo class which you use everywhere.
This isn't a problem - it's a feature.
They are two independent classes. Compare the two, and notice that the proxy class has none of the constructors, methods, indexers, or other behavior from the original class. This is exactly the same thing that would happen if you consumed the ASMX service with a Java program.
Seems like you have two different classes on both ends. Your application has ContactInfo class and your webservice also have the ContactInfo class. Both are two completely different classes. One way is to use the WebService class on your side. If you are using ContactInfo inside your web service then it will be serialized and will be available on the client side for use.
You can also modify your References.cs file generated by Visual Studio when the web reference is added. If you remove the proxy generated classes and add a reference (using statements) to your personal classes, you'll be able to use them straight away, without shallow copy / reflection or heavy mapping. (but you'll have to re-apply your modification if you regenerate the proxy layer).
I also tried to serialize the proxy object and deserialize them back in my DTO classes but it was quite heavy resources wise so I ended up modifying the References cs generated layer.
Hope it will help other people coming here :)
Kindly.

Categories

Resources