I am using this example to get the SOAP interface working on my Magento 1.9 shop. And it all seemed to work okay, I can add the service reference, and I get a MagentoSOAP.com.example.myshop namespace added. (MagentoSOAP is the namespace of my project).
But, according to the example given, I should have a MagentoService available in that namespace, but it is not there. I can see all the classes in the MagentoSOAP.com.example.myshop namespace, but no service.
I know the SOAP API works, because in PHP I get response from it.
I am using Visual Studio 2015.
The class you want is not MagentoService but PortTypeClient:
using MyNamespace.com.example.shop;
...
PortTypeClient client = new PortTypeClient();
string sessionId = client.login("user", "api key");
// example call
var result = client.catalogInventoryStockItemList(sessionId, new string[] { "SKU" });
Related
I have a plugin model architecture that creates my Restful WCF services.
(It will be a couple years before we move to Web Api from WCF so, moving to Web Api isn't exactly a solution.)
I have decoupled WCF Microservices that don't reference each other.
EntityAWebService
EntityBWebService
EnityAWebService knows that a service EntityBWebService exists from a configuration, but doesn't reference it.
EntityAWebService and EntityBWebService are plugins. As such, they could be on loaded on the same site.
EntityAWebService makes a call to EntityBWebService using configuration information. The EntityBWebService could be on the same server or a different server.
- If on a different server, the code will continue to use HttpClient.
- If on the same server, go cract the message and send it through the channel without going through HttpClient, operating system's network, and IIS.
Below is the architecture. The orange is what I want to create.
Using HttpClient means EntityAWebService sends a message that is going to hit the operating systems network layer and go through IIS. Neither of which is necessary. It causes performance issues, and as the Entity plugins increase, so does the number of sockets and even using a singleton httpclient, the sockets are leaking.
The orange in the architecture is what doesn't exist yet.
The code knows the Url to call for Entity B Web Service, the message content, and the headers. How would I simulate, in the code represented by the orange box, what IIS does to forward the call through the behaviors and to the Endpoint?
FYI, my current project is too complex to post, so I will create a sample and post it soon.
Sample project: https://github.com/rhyous/DecoupledWcfServices
Turns out I didn't need to use named pipes. However, investigating how to use named pipes taught me what I needed to know. I just needed to use reflection and ChannelFactory. As the ChannelFactory for IIS hosting already exists, named pipes would be redundant.
Example Project here: https://github.com/rhyous/DecoupledWcfServices
And the appropriate snippet (the meat of the solution) is below.
using System;
using System.Collections.Specialized;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Web;
namespace DecoupledWcfServices
{
/// <summary>
/// Service 1 and Service 2 are in the same namespace in this project
/// </summary>
public class MessageBus
{
public string CallOtherWcfService(string url, object content, NameValueCollection headers)
{
var service = GetServiceName(url);
try
{
var netPipeUrl = $"http://localhost:54412/{service}/{service}.svc";
var serviceContractType = typeof(IService2);
var genericChannelFactoryType = typeof(WebChannelFactory<>).MakeGenericType(serviceContractType);
var binding = new WebHttpBinding();
var channelFactory = Activator.CreateInstance(genericChannelFactoryType, binding, new Uri(netPipeUrl)) as WebChannelFactory<IService2>; // I actually won't know it is an IService2 in my project, but getting this far should be enough
var proxy = channelFactory.CreateChannel() as IService2;
using (new OperationContextScope((IContextChannel)proxy))
{
var task = proxy.GetData("some data"); // Might need more work here to know which method to call based on the Url
task.Wait();
return task.Result; // Serialized JSON
}
}
catch (Exception)
{
throw;
}
}
internal string GetServiceName(string url)
{
var index = url.IndexOf(".svc");
var sub = url.Substring(0, index);
index = sub.LastIndexOf("/") + 1;
var sub2 = url.Substring(index, sub.Length - index);
return sub2;
}
}
}
I am bit curious about one thing which has happen while trying to understand the concept of Service References and Web Service References.
What I did is?
In my project I have added a web service as a Service Reference and trying to get my script run through the use of client.
But while getting result it is throwing an exception as in the following image:
I have tried to trace out the cause but not able to get the proper answer for that.
I have following code for the resultant object.
[
ComVisible(false),
Serializable,
SoapTypeAttribute("RecordList", "http://www.someadd.com/dev/ns/SOF/2.0"),
XmlType(TypeName="RecordList", Namespace="http://www.someadd.com/dev/ns/SOF/2.0")
]
public class MyRecordListWrapper
{
private IxRecordList recordList = null;
private const string XMLW3CSchema = "http://www.w3.org/2001/XMLSchema";
[SoapElement("Headers")]
public Header[] Headers = null;
[SoapElement("Records")]
public Record[] Records = null;
// some methods to work on intialization
public SmRecordListWrapper(ref IxRecordList p_RecordList)
{
recordList = p_RecordList;// record list initialization
Headers = CreateWrapperHeaders(); // will return header class object
Records = CreateWrapperRecords(); // will return record object
}
}
Can anyone tell me why this error is showing for me?
While adding reference as a Web Service Reference
when I add the same reference as a web reference that time the program is not showing any error and runs successfully?
So can anyone tell me what is the difference in working with the same code using service reference and web service reference?
and Which is a correct way to ass references?
Hope I will get some more described answers to make the things easy to understand.
Thanks in advance.
Adding a web reference, visual studio uses xsd.exe to generate the classes from the service metadata. This uses XmlSerializer under the hood.
Adding a service reference, visual studio uses svcutil.exe to generate the classes from the metadata. This uses DataContractSerializer under the hood.
Two separate tools, two outcomes. For general information, DataContractSerializer is a lot less forgiving when it comes to generating classes from metadata.
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).
I have a class that is designed to work with a web service. For now, I've written it to query http://www.nanonull.com/TimeService/TimeService.asmx.
The class is going to be used by a legacy app that uses VBScript, so it's going to be instantiated using Namespace.ClassName conventions.
I'm having trouble writing the code to get bindings and endpoints working with my class, because I won't be able to use a config file. The samples that I have seen discuss using SvcUtil.exe but I am unclear how to do this if the web service is external.
Can anyone point me in the right direction? This is what I have so far, and the compiler is crashing on IMyService:
var binding = new System.ServiceModel.BasicHttpBinding();
var endpoint = new EndpointAddress("http://www.nanonull.com/TimeService/TimeService.asmx");
var factory = new ChannelFactory<IMyService>(binding, endpoint);
var channel = factory.CreateChannel();
HelloWorld = channel.getCityTime("London");
Darjan is right. The suggested solution with the web service works. The command line for proxy generation with svcutil is
svcutil.exe /language:cs /out:generatedProxy.cs /config:app.config http://www.nanonull.com/TimeService/TimeService.asmx
You can ignore app.config, however add generatedProxy.cs to your solution. Next, you should use TimeServiceSoapClient, take a look:
using System;
using System.ServiceModel;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
TimeServiceSoapClient client =
new TimeServiceSoapClient(
new BasicHttpBinding(),
new EndpointAddress("http://www.nanonull.com/TimeService/TimeService.asmx"));
Console.WriteLine(client.getCityTime("London"));
}
}
}
Basically that's it!
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.