C#/ASP.NET Core - Internal and external controller logic - c#

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?

Related

IHttpClientFactory in .net core

I wanted to use IHttpClientFactory in my .NET Core project. The problem is that there are bulk of APIs that I need to consume. So should I use a single Typed Client for all the API's or should bifurcate those? All the API requests are to the same source.
public interface IStudentClient
{
}
public class StudentClient : IStudentClient
{
}
services.AddHttpClient<IStudentClient, StudentClient>();
I have followed the above structure and was planning to include all the API's inside IStudentClient and implement those in StudentClient. Now my question is, won't this will make the StudentClient more complex class when including all the API's implementation in only one class.
In my opinion writing one big typed client for all the access to a specific remote service is the right way to go. That's exactly the usage pattern envisioned by Microsoft for the typed http client.
At the same time I understand your concern, but the situation il less desperate than you might think it to be.
First of all you will get a huge interface and, consequently, a huge implementing class, but the responsibility of them is clear: the typed client has the responsibility of defining a proxy to access a remote web service (the student service in your example).
The typed client class isn't indeed complex: it can be huge, for sure, but it's stateless and just exposes methods to access the endpoints of the remote web service. Each method has a clear and well defined responsibility: accessing a specific endpoint on the remote web service; code like that is rarely complicated.
The only concern is consuming the interface IStudentClient from a controller or a service. The interface is huge, so if you inject it as a dependency in a consumer class you will violate the interface segregation principle. A possible solution for this problem is modeling smaller interfaces, shaped for the specific needs of the consumer classes.
Imagine that one of the endpoints exposed by your remote web service lets you get the details for a single student (it could be something like GET /students/{studentId}). This means that one of the methods exposed by IStudentClient will be GetStudentById(Guid studentId) which wraps the GET request to /students/{studentId}.
At this point you can define a smaller interface called IStudentProvider, shaped like this:
public interface IStudentProvider
{
StudentContract GetstudentById(Guid studentId);
}
Now you can inject the smaller interface IStudentProvider in your consumer classes (for example an MVC controller or a service class that you define in your application).
To implement the interface IStudentProvider you can do the following:
public class HttpStudentProvider : IStudentProvider
{
private readonly IStudentClient client;
public HttpStudentProvider(IStudentClient client)
{
this.client = client;
}
public StudentContract GetstudentById(Guid studentId)
{
return this.client.GetStudentById(studentId);
}
}
IMPORTANT DISCLAIMER: in order to keep the discussion simple I didn't use the Task class on the interfaces, but of course all of the methods should return Task<T> and accepts an instance of CancellationToken as a parameter, because http calls are natural asynchronous operations and you do not want to perform blocking calls with your http client.
How to register these classes on the DI container
The Microsoft DI container will offer you some extension methods to register a typed client. The service will be registered as a transient dependency, so each other service depending on it must be registered as a transient dependency too (in order to avoid the captive dependency issue).
This is the way you should register your services:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient<IStudentClient, StudentClient>();
services.AddTransient<IStudentProvider, HttpStudentProvider>();
}

Can I use a web api from a web application as a service reference?

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.

How can I work against two different versions of a web service?

My project is a consumer for a 3rd party web service (old school web service vs. WCF service), and it has two versions, the "sandbox" (staging), and prod services. The APIs on these services are almost identical, and I am looking for a way to cleanly switch between the two versions, preferably without using conditional compilation.
I instinctively rushed off and extracted an interface from the client generated by Visual Studio's "Add web reference", i.e. AgentImport but that class is not partial, so I can't make it derive from the interface, or from any other superclass. I already have the creation of AgentImport instances nicely encapsulated in an abstract base for all my clients of AgentImport, but without using more risky compiler directives, how can I switch between v1 and v2 of AgentImport?
Some code:
using Clients.PrivateProperty.AgencyServicesApiService;
namespace Client.PrivateProperty
{
public abstract class PrivPropFacilityBase
{
protected static AgentImport Client;
protected PrivPropFacilityBase()
{
Client = new AgentImport();
Client.Timeout = 10000;
}
protected virtual AgentImport GetClient()
{
return new AgentImport();
}
}
}
I have tried adding service references instead of web references, as advised in comments below, to at least get access to partial classes, but when I add the first service reference, for the production service, and extract an interface from the auto-generated SOAP client, i.e. IAsapiClient, that interface references objects declared in other auto-generated classes, in the same namespace as the client, e.g. SecurityToken:
void UpdateUniqueAgentID(string PrivatePropertyAgentId, string AgentId, AgencyServicesApiService.SecurityToken Token);
If I add the second service reference, for the staging service, that second auto-generated SOAP client references objects in its own namespace, e.g. now it uses AgencyServicesApiSandbox.SecurityToken, so my compiler tells me that it doesn't implement the interface I extracted the first time. I am then left with the messy business of having to extract an new interface for each object that the main interface, IAsapiClient, references, so that this main interface only uses the extracted contracts, not actual class names.
In pursuing the above< I have reached the conclusion that my only feasible, and lowest risk, way forward is to use two client projects, one specifically for the production service, and one for the staging service. Then, at execution time, I only need to worry about dynamically choosing between two well known, i.e. not auto-generated, client objects.

Passing additional information from SoapExtension to WebMethod implementation

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; }
...
}

WCF: Best practice to send Form Data to a Web Service?

We are using C#, ASP.NET & WCF. I am trying to send form data to a web service which in turn inserts/updates a database with the data from my form. How should I send over my data?
We have the forms populated fine but are having some issues with sending updates back to the web service. We have determined that it is not great practice to use datasets in this situation, it is slow and we have to do too many SELECT *'s for our liking.
I have about 15 fields that need to go across. One team member wants to pass everything as a parameter which I dont think is optimal. We tried sending everything across in an Object[] array but are receiving a weird error "Type 'System.DBNull' with data contract name 'DBNull:http...' is not expected. Add any types not known statically to the list of known types",
Any suggestions are most welcome.
We use WCF to define our Data Contracts and Data Methods using attributes.
Basically we create an assembly to define all our classes and another assembly to provide the WCF connective bits
OPur class assembly contains a service class and several message classes.
We define an interface for our service and mark it up with relevant WCF markup. This is our Service Contract.
[ServiceContract]
public interface IExampleWebService
{
[OperationContract]
CreateAccountResponse CreateAccount(int parameter, CreateAccountArguments another parameter);
[OperationContract]
DeleteAccountResponse DeleteAccount(int parameter);
}
We implement this interface in a class and we create various data contracts (our response and argument classes).
[DataContract]
public class CreateAccountResponse
{
[DataMember]
public bool CreatedOk { get; set; }
[DataMember]
public int AccountId { get; set; }
}
These classes are exposed to our form using the Web Service (We create another assembly as a web service and have a class that inherits from our Service Class (not shown in this example) so we let Visual Studio do all the work setting up the WCF service as we reap the benefits with an easy to use and maintain Web Service.

Categories

Resources