Due to network architecture of our software, our application servers cannot connect directly to the web service of our customer. Because of this we have an integration server between the application servers and customer's servers. This integration server hosts a proxy web service. The problem is that the necessary credentials and some other additional information needs to be passed from the database at our application server to our proxy web service at the integration server.
I wouldn't want to pollute the API and pass the object containing credentials and additional information on each web service request. Additionally we have multiple integration servers which can be shut down at will so I cannot just initialize the web service with credentials and other information in a separate method because the subsequent web service requests might be passed to another integration server.
Is there a way to add some kind of SoapExtension which could be used to pass the information to my web service instance on each method? If not, is there something else I could do besides adding an argument to each web method and use that to pass the information?
The answer was actually quite obvious.
Firstly I need to create a class which is derived from SoapHeader. This class is used to store all credentials and other additional information. For easier explaining, let's give this class a name CredentialContainer.
In the actual web service class we need to add a new public property of type CredentialContainer. The property in this example is named Container.
Lastly, we have to add new attribute called SoapHeader to each method with WebMethod attribute. This handles transferring the information passed in the header of SOAP message to our CredentialContainer instance. Because new web service instance is created for each web service request, there are no risk even with multiple concurrent web service requests.
Here's the example code:
[WebService]
public class ExampleWebService
{
public CredentialContainer Container { get; set; }
[WebMethod]
[SoapHeader("Container")]
public void PerformSomething(string value)
{
var actualWebServiceClient = new MyWebServiceClient(Container.Url, ...);
actualWebServiceClient.SendValue(value);
}
}
public class CredentialContainer : SoapHeader
{
public string Url { get; set; }
...
}
Related
Our project consists of several ASP.NET projects which are microservices. There is a service that is in charge of authentication only, and then sends the requests down stream to the appropriate service.
The microservices are exposed only locally, so they assume that the request is authenticated and expose various controllers that the authenticator service can call.
However, we also expose "internal" controllers that we can call by using a debug endpoint that can only be accessed through VPN.
To differntiate between the internal and external controllers, we simply put them under different namespaces with the same name, but the internal controllers are prefixed with a dot (e.g. GET /.accounts for internal, and GET /accounts for external).
For the contracts classes, we use a subclass. For example:
public class CreateAccountRequest
{
[Required]
public string Name { get; set; }
public class Internal : CreateAccountRequest
{
public bool SomeRequiredInternalFlag { get; set; }
}
Then you can use the external/internal classes respectively.
The issue we are facing is the services themselves. For example, the AccountService has a CreateAsync method to create a new account with certain logic. However, the internal create account method needs a different logic.
The solutions we thought of:
Make the services classes partial with different names. For example, the external accounts service named AccountsService.cs and contains the external methods (e.g. CreateAsync(CreateAccountRequest request) and the internal accounts service named AccountsService.Internal.cs, and contains the internal methods (e.g. CreateAsync(CreateAccountRequest.Internal request).
Create a separate class for the internal service, with the same dependencies, and register it through the DI.
Create a subclass for the internal service methods, and expose an Internal property which is an instance of that subclass.
Do you guys have other ideas maybe?
I have inherited a web service built to receive calls from a third party system, "System A". It was a POC that may not have any active functions calling it and I suspect it was only tested from SoapUI or the like and never from the application it was designed for.
When System A is configured to call it, the service is called but the payload, one complex-type parameter, is null.
I have two other web services written years ago that accept calls of the same type from the same function of System A. Pointing System A to either of these services results in the parameter being supplied. Contracts and WSDLs look very similar and the only variations I see (like differing namespaces) seem to vary between the two services that do work.
What would cause a web service to not receive the payload in the call?
Related, where should I look to find it? The parameter is getting dropped between System A calling and the web service code itself getting hit. I've checked the trace logs but see nothing that I recognize as useful.
namespace MyNamespace.StandardNoteReceiverService
{
public class StandardNoteReceiverService : IReceiveNoteService
{
public StandardNoteReceiverResponse ReceiveNote(ReceiveNoteData standardNoteReceiverRequest)
{
string x = standardNoteReceiverRequest == null ? "NULL" : "ok";
LoggingLib.Log($"Service called. Paramter status: {x}");
return NoteReceiverServiceLayer.ReceiveNote(standardNoteReceiverRequest);
}
}
}
which implements
namespace MyNamespace.StandardNoteReceiverService
{
[ServiceContract]
public interface IReceiveNoteService
{
[OperationContract]
StandardNoteReceiverResponse ReceiveNote(ReceiveNoteData standardNoteReceiverRequest);
}
}
It turned out to be the parameter naming. Once I changed the name of the parameter to be the same as the name used by the services that are working, it began receiving the data.
public class StandardNoteReceiverService : IReceiveNoteService
{
public StandardNoteReceiverResponse ReceiveNote(ReceiveNoteData NoteData)
{ ...
How did you build “System A”? Is it a WCF Web HTTP service or an ancient soap web service? How does the client call the service and send the parameter? I think it may be that the format of the parameters sent by the client is incorrect. In the Rest-style service created by WCF, using complex objects as parameters to pass data may not always receive the value of the parameter on the server because of the format of the parameter.
Get the object is null using JSON in WCF Service
While in the WCF SOAP web service, the invocation is completed with a client proxy, the parameters are strong-typed. If the server always gets null, it might be caused by other issues.
I suggest you create a minimal, producible example so that I can try to offer a workaround instead of offering speculation of this issue here.
Feel free to let me know if the problem still exists.
Is it possible to add as a reference and call an APIs controller methods as a service on another project? What are the alternatives if this is not possible?
Web API types of applications do not have a 'service reference' anymore. They do not produce WSDL, so you cannot add them like you used to do with SOAP services. No proxy classes are generated... no intelli-sense.
Web APIs are typically called with lightweight http requests and return JSON and not XML based SOAP responses like traditional ASMX or SVC (WCF) services.
You have some reading to do I believe.
To answer your question, you CAN indeed call API services from a web application (say a controller method in an MVC app), but you won't have proxy classes to help you.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client
When you create a service reference you end up with a reference to an interface and a client class that implements the interface.
You can follow pretty much the same pattern without a WCF service reference. In fact, that's one of the benefits of depending on an interface. It doesn't matter to your application whether the implementation is a call to a WCF service, an API, or anything else.
First declare an interface that describes how you will interact with the API.
public interface ISomethingService
{
public SomeData GetSomeData(string id);
}
That interface is what your other classes depend on. They'll never know what the implementation is.
Your implementation could be something like this. I'm using RestSharp to create the API client because I like it better than managing an HttpClient:
public class SomethingServiceApiClient : ISomethingService
{
private readonly string _baseUrl;
public SomethingServiceApiClient(string baseUrl)
{
_baseUrl = baseUrl;
}
public SomeData GetSomeData(string id)
{
var client = new RestClient(_baseUrl);
var request = new RestRequest($"something/{id}", Method.POST);
var response = client.Execute<SomeData>(request);
return response.Data;
}
}
In your startup you would register this class as the implementation of ISomethingService and pass the base url from configuration. That would also allow you to pass a different url for development, production, etc. if needed.
Ultimately it's no different from depending on a WCF service. One difference is that a WCF service defines an interface, but in this case you have to do it. That's actually a good thing, because it's better for your application to define its own interface rather than directly depending on the ones someone else provides. You can wrap their interface or API in a class that implements your own interface, giving you control over the interface you depend on.
I'm developing an .NET application (WinForms, .NET Framework 4.0) and i need to call a method from a web service.
The problem is that the client's web service is only accessible from inside its network. So at development time, i can't access it, so I can add it as a refference.
How should I proceed?
Should I create some kind of replica of that web service in my network?
Which would be the best option?
I'd get the WSDL and write a mock of it that i can call from my side.
I'd then make it return data that i was expecting and then later on have it return data that i wasn't expecting.
Then when you deploy it (should) be ok but you would need to run some integration tests.
The alternative it to tell them to open a port for you to use so that you can write the s/ware.
You could replicate the web service which returns dummy data.
I would wrap the call to the service in a separate abstraction layer, this would allow you to provide a different implementation if you wish during testing.
Eg. Something along the lines of..
public interface IXYZServiceInvoker
{
SomeData SomeServiceCall();
}
public class SomeServiceInvoker : IXYZServiceInvoker
{
public void SomeServiceCall()
{
//Calls a real service
}
}
public class FakeServiceInvoker : IXYZServiceInvoker
{
public SomeData SomeServiceCall()
{
//returns some dummy/test data
}
}
I have a WCF service and methods are exposed as below:
public interface IService
{
[OperationContract]
bool Read();
[OperationContract]
bool Write();
}
public class MyService : IService
{
//Constructor
MyService()
{
//Initialization
}
public bool Read()
{
//Definition
}
public bool Write()
{
//Definition
}
}
I have a desktop based application that consumes the Web service through URL.
This web service can be deployed at multiple location so user can connect to any web service by choosing a url from the combo box.
In the client application I create a Service client dynamically as shown below:
ServiceReference1.DXMyServiceClient _client = null;
_client = new DXMyServiceClient ();
_client.Endpoint.Address = new System.ServiceModel.EndpointAddress(url);
Questions
While debugging I notice whenever I call any methods of web service each time the constructor of MyService is invoked ( if I am connected to the same service).
like for example when I do:
_client.Read();//MyService () constructor is called
_client.Write();//MyService () constructor is called
The problem is I have to do all the initialization again.. like if I connecting to the database then I have to again build the connection string and all stuff..
Is this the natural behavior or I am doing something wrong?
Secondly,
I want to validate user for the valid url ( of web service ). If it is connecting to the valid url or not.. I am doing that through Ping command..
What is the best approach for that!!
Questions While debugging I notice whenever I call any methods
of web service each time the constructor of MyService is invoked
(if I am connected to the same service).
The problem is I have to do all the initialization again..
like if I connecting to the database then I have to again
build the connection string and all stuff..
Yes, that's the default behavior, and the recommended behavior. You should NOT rely on any state on your service side! That is generally not a good idea and can lead to a multitude of problems.
In its recommended "per-call" mode, a WCF service has a ServiceHost() class instance running, which will listen for incoming requests / messages. Each time a request comes in, a new, fresh instance of the service class (that implements your service contract) is constructed to handle the request - just like each time you hit a URL in ASP.NET, your page class is instantiated to handle the request.
Yes, of course - this means you should keep your service classes simple and lean and not do a lot of initialization / state management. Anything that needs to be persisted between service calls should be put in a persistence store, like a database, anyway.
You should look at the ServiceBehaviorAttribute class and it's InstanceContextMode property. It controls the lifetime of your service object.
The problem is I have to do all the
initialization again.. like if I
connecting to the database then I have
to again build the connection string
and all stuff..
Is this the natural behavior or I am
doing something wrong?
By default InstanceContextMode is set to PerSession and ConcurrencyMode is set to Single. However, if you don't use session, basically every time you call service new instance is created. This is desired behavior because it is considered more scalable. If it is a problem for you, you should implement session between subsequent calls then for every session you will get one instance of your service.
Here is a guide how to do that: Using Sessions.