I have inherited a couple of large legacy C# code bases that make extensive use of SOAP/WCF to talk to each other and some third party software. I am somewhat new to WCF. I've run across a situation I can't quite explain. The URL pattern being used for the contracts in one of the service classes is definitely invalid (The top level domain it specifies does not exist).
[OperationContract(Name = "TestMethod", Action = "http://hard.coded.URL.that.is.definitely.invalid/TestMethod")]
[WebMethod(MessageName = "TestMethod")]
[System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults = true)]
string TestMethod(string x);
Is it possible that this could work, or is the explanation simply that it has never been used?
I don't know for sure that this service has actually been used for anything. The commit messages on all revisions of this file (and most other files) are useless. This is in one of the modules that talks to third party software that I don't currently have the ability to deploy in a test environment. There are a lot of other WCF endpoints in the project that use valid URL patterns.
Maybe they were doing something really weird with the DNS configuration(?) This service most likely would be run over a local network.
Related
I have to consume some service on ESB which has addresses:
for dev env: http://esbdev.com:11111/ws/ir.channel.aaa.pub.ws:ConsumeMeV1
for test env: https://esbtest.com:22222/ws/ir.channel.aaa.ws:DoAmazingCalc
Functionality is the same.
Can I somehow have only one common code (to rule them all) in c# generated from WSDL and manipulate to which env I’m connecting by some config?
And can i switch freely between http on dev and https on test environment?
Now I’m calling it on dev like:
using (ConsumeMeV1_PortTypeClient client = new ConsumeMeV1_PortTypeClient(this.EsbEndpointBinding, this.EsbEndpointAddress))
But there is dev name hardcoded - how should i map ConsumeMeV1 to DoAmazingCalc on test?
On test I'm calling it like:
using (DoAmazingCalc_PortTypeClient client = new DoAmazingCalc_PortTypeClient(this.EsbEndpointBinding, this.EsbEndpointAddress))
Can I generate common clases like:
using (BestServiceNameClient client = new BestServiceNameClient(this.EsbEndpointBinding, this.EsbEndpointAddress))
The best option for me is to get endpoint/names config from database and inject to clinet class - but how?
Ok, I know where the minuses come from.
No part of the address matters as long as the functionality underneath it does not change. So both generated classes will allow you to use them with each of the given addresses. I note that these obvious things are like that only when you know about it, so I'm sorry that no one even wrote a word about it.
However, when it comes to https, it depends on the BasicHttpBinding.Security.Mode settings. You can set Transport for https and TransportCredentialOnly for http. The corresponding value can be saved and retrieved from the database or other configuration together with the user and password.
I use the above with the setting:
BasicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
I am currently working on a school project with a classmate. We've decided on making the classic setup of an Administration-client (Blazor Server) and a Member-client (Angular).
We have 7 Projects in the solution so far:
Solution
├───Project.MemberClient (Angular)
├───Project.AdminClient (Blazor Server)
├───Project.Api (REST API)
├───Project.Application (CQRS & Mediatr)
├───Project.Core (Entities, Enums, Interfaces)
├───Project.Infrastructure (Database Context & Migrations)
└───Project.Test
We're using EntityFramework for the database, which both the API and Blazor Server have access to, through Mediatr.
Unfortunately, we can't come to terms with how we should handle the use of the API.
My classmate is convinced that both Blazor Server client and the Angular client should go through the REST API.
I'm convinced that we don't need to go through the API with the Blazor Server-client, since it can access Mediatr through Dependency injection. I feel it's silly to go through the API to deserialize a C# object to JSON just to serialize it again straight after.
This is a request on the API:
[HttpPost("organizr-user")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<OrganizrUserResponse>> CreateOrganizrUser([FromBody] CreateOrganizrUserCommand command)
{
var result = await _mediator.Send(command);
return Ok(result);
}
This is a request on Blazor Server:
private async Task OnButtonSave_Clicked()
{
_userCreated = false;
_showErrors = false;
var query = new RegisterUserRequest
{
FirstName = _firstName,
LastName = _lastName,
Gender = (Gender)_gender,
Address = _address,
PhoneNumber = _phoneNumber,
Email = _email,
Password = _password,
ConfigRefreshPrivilege = _refreshConfiguration
};
var result = await Mediator.Send(query);
if (!result.Succeeded)
{
_showErrors = true;
_errors = result.Errors.ToList();
}
else
{
_userCreated = true;
}
}
I feel (yeah, there are a lot of feelings involved) like we still uphold the principle of only one access point by the use of Mediatr. Blazor doesn't need the API, but Angular does.
What would be the right way to go about this?
I am glad you are taking this school project so seriously.
As is with all architectural decisions - "it depends". There is no such thing as a silver bullet approach, only the best for you situation.
I think you both have some points. You are correct in saying you are upholding a single point of access, and thus reducing the amount of code you need to write - but that is not the only thing to consider here. You need to ask yourself a few more questions.
You should treat this as an production application that has the potential to scale
Here are some questions you should ask yourself.
Are the API and the Blazor web server going to be hosted on the same server as the database ?
API's should be stateless, are you going to keep that consideration while writing your blazor web app, since they consume the same code ?
Is your application scalable ? How will you implement things like load balancing on both the API and the blazor web server ?
Can I easily replace/change some in the overall design if needed ?
If I had to choose for you, I would suggest filtering everything through a web API.
Here is why:
You have more options around hosting - you can host your blazor web application on one server and the database/webAPI on another.
It forces developers into "The pit of success". If you have 10 developer working on this product, it's easier for them to think of the application as "one API" rather than an "API and a server that uses the same code". This may not seem important now, but trust me, large scale application can get very hairy very quickly if you don't keep things as simple as possible.
Creating load balancers on Blazor web server can be tricky, since it uses SignalR to communicate with the client.
Testing becomes easier. What if your blazor application has functionality that your Angular client doesn't? That means it would never be built into the web api. Now you need to do things like load testing, stress testing, etc on two separate servers rather than just the web API. The testing required on the Blazor web server would be heavily scaled down if everything ran through the Web API.
And last but not least,the Blazor developers pride themselves on how easy it is to switch between Blazor client and Blazor web server. What if, in future, you decide that Blazor web server isn't the best solution, and you would prefer blazor client ? If everything was running through an Web API this would be a few lines of code. If not - you have a lot of refactoring to do.
I think its a better idea to write a few extra lines to "serialize and deserialize " through an API now, and save yourself potential hassle later.
This is my opinion based off my personal experiences - keep things simple, readable and scalable.
I hope this helped.
Let me know if you would like me to clarify anything.
Happy coding!!
I'm new to Web Services from C#, but have worked C# for years, just never needed to use Web Services. Due to privacy issues, I can't disclose actual URL, but there is a test server and a production server where the web services are identical in all other respects, and the services were written / managed by another entity.
https://LiveSite.SomeDomain.com/FolderInWebSite/TestWebServiceSoapHTTP
and
https://TestSite.SomeDomain.com/FolderInWebSite/TestWebServiceSoapHTTP
Do I need to create two separate web references to the project and create different instances of them to go, or can I via some property just change which URL version it is sending data to.
Additionally, not being familiar working web services, I see the classes as Visual Studio imported. I can create instances of the classes and set the applicable properties (int, dates, strings, string[] arrays, etc). But not seeing how to actually say ... Go send it now. and then getting the response back.
I've done this from an older application with another language and was doing direct with HTTP and SOAP where I was able to make my own connection to the URL, build the body of the SOAP message, then send it.
Just use the "Url" property.
var myProxy = new MyProxy();
myProxy.Url = "http://foo.com/myservice";
Edit for second part of the question:
There should be a method for each action exposed the API that you can call. For example if the API exposes a MyAction that takes a string, the code generator should have generated a method that you can use like so:
myProxy.MyAction("hello");
I have two websites, both using .Net framework 3.5. One website is hosting a soap web service and the other is referencing this service.
I'm having some unexpected happenings with my web method signatures. I have a simple method in my web service with a signature such as:
[WebMethod]
public string[] HelloWorld()
{
return new[] { "Hello World" };
}
But when I reference this web service using the 'Add Service Reference' feature in VS2008, with configuration set to "Always generate message contracts" (although when i check the 'reuse types in referenced assemblies', i seem to have the same issue), the signature seems to be changed by the auto generated proxy objects to the following:
HelloWorldResponse HelloWorld(HelloWorldRequest request)
I've tried to look this up on the net, but having trouble finding something that will simply explain to me why this is happening, and whether I can/should try to work around it?
I also have this question:
How does one determine whether they should choose the service reference configuration option to "reuse types in referenced assemblies" and "always generated message contracts"?
The message-contracts option might have this effect; the purpose here being to allow fine-grained control over the underlying request. Ultimately, what you are sending (behind the scenes) is a request payload.
The reuse-types option is more typically used with objects (not things like string[]) - and means that if you have a 100% matching Customer (say) class locally, it can re-use that for the web-service rather than generating a proxy type.
Additionally, note that you aren't actually consuming a WCF service ([WebMethod] is the older web-service style). As such you may have better results with a "Web Reference"; when adding the service, hit "Advanced", then "Add Web Reference...". This uses the older UI and wsdl.exe to generate code intended for [WebMethod] (asmx), rather than WCF (svc).
Of course, rather than hosting a [WebMethod], you could (since the server is also 3.5) host a WCF service; this may make things easier.
A final point of WCF; if you really want the same contract at client and server, you can use either assembly or class sharing to use the very same types at both end. This is not supported for [WebMethod], though.
We have an existing ServiceContract
[ServiceContract(Namespace = "http://somesite.com/ConversationService")]
public interface IConversationService
{
[OperationContract(IsOneWay = true)]
void ProcessMessage(Message message);
[OperationContract(IsOneWay = true)]
void ProcessMessageResult(MessageResult result);
}
and we need to add a method to it
[ServiceContract(Namespace = "http://somesite.com/ConversationService")]
public interface IConversationService
{
[OperationContract(IsOneWay = true)]
void ProcessMessage(Message message);
[OperationContract(IsOneWay = true)]
void ProcessMessageResult(MessageResult result);
[OperationContract(IsOneWay = true)]
void ProcessBlastMessage(BlastMessage blastMessage);
}
Will this break any existing wcf clients that are using this service? Or will we have to update all existing wcf clients?
EDIT: This service is using both netTcpBinding and netMsmqBinding
I think your existing clients will continue to work. After all this is very similar to SOAP and web services in that the client will connect to the given URL and request a specific service. If you take methods away you will risk breakage (only if the method is used I believe) but adding should be pain free.
I've only dabbled in WCF but have used the ASP.NET web services in this way to great success.
I just tested this with a WCF client Windows app (UWP) and it continued to work after updating the WCF service application. So no: as previously answered, your clients will not break when you add a method.
I thought it was worth mentioning, however, how easy it is to update your service clients with Visual Studio 2015:
Make sure your WFC service is running.
Simply go to the Solution Explorer,
Expand Service References
Right-click on your service reference
Click Update Service Reference
If you get an error message, repeat the last step. I had to try a few times for some reason.
No, I wouldn't expect that - adding new functionality / new service methods that does NOT alter any of the existing methods / function calls will not affect "old" clients. Of course, they won't know about the new methods until their proxies have been recreated from metadata, or adapted manually.
But existing calls should be unaffected, as long as their signature (the data they exchange) stays the same.
Marc
I take the more extreme view on this. Why ever change anything? Instead, why not create a new contract, inheriting from the old, and adding the new operation? The new contract can be exposed in a separate endpoint in the same service.
It may be paranoia uninformed by formal proof, but it seems to me that, if it's possible to construct a client that can tell the difference, then it's possible that some client will "break" when you make the change. Consider that, when you change the service contract you're not just changing service code - you're changing the proxy code in any client that happens to update his service reference. Some, more conservative customers, might consider that a reason to re-test their client code - after all, they may well have rules that say they have to retest their code whenever any change is made to it.
The existing client will be referring to the original endpoint, so will not be affected by adding a new endpoint - no code would change if an "Update Service Reference" was performed.
Besides, why even think about it, if you don't have to?
In general, adding to a message in SOA solutions does not break the contract. I believe that as long as you're not using a binary protocol (net.tcp), you'll maintain backward compatibility.
I'm not sure about whether or not it will break your clients using binary bindings, though?