I am consuming third party APIs in which I fetch base URL from my configuration file (appsettings.json).
While creating dynamic endpoints I concatenate URL as follows:
$"{BaseUrl}/api/v1/users/{id}/apps"
Now problem is I got feedbacks on this as hardcoding and it is also hard to maintain for future modifications.
Is there any better approach for managing third party APIs endpoint or URLs?
Use static class to manage URLs.
static class ApiRoutes {
private const string Base = "Api"
Private static Class ControllerOne {
public static string Get = Base +"\ControllerOne\{id}"
public static string Post = Base +"\ControllerOne\{id}"
}
Than In your Controller,
You can do something like that:
[httpGet (ApiRoutes.ControllerOne.Get)]
Get (string something) {
/*your code*/
}
[httpPost(ApiRoutes.ControllerOne.Post)]
Post (string something) {
/*Your code*/
}
Then, if you will have the desire to change the URL in the future, it will be much easier!
Related
How can I create a global variable in an ASP.NET Core Web API application? In ASP.NET MVC, I could do it like:
Application["<variableName>"] = <value>
I tried the same in my web API application, but was unable to find an equivalent for this. I saw some solutions which suggested me to store the data appsettings.json, but since the data I want to store in the global variable is not static, I cannot use that setup. I need to set different data during runtime. How can I do that? Please help me.
We could use Singleton_pattern , creating an Application static object in .net core.
we can also try to use Depend Injection, register a singleton object as below in your code.
Writing a property ConcurrentDictionary in ApplicationInstance class.
public class ApplicationInstance {
public ConcurrentDictionary<string,object> Application { get; } = new ConcurrentDictionary<string, object>();
}
public void ConfigureServices(IServiceCollection services){
services.AddSingleton<ApplicationInstance>();
}
Then we might use this object
public class HomeController : ControllerBase
{
private readonly ApplicationInstance _application;
public HomeController(ApplicationInstance application)
{
this._application = application;
}
//use _application["test"] instance in your code
}
I would use ConcurrentDictionary to help us avoid racing-condition which will be happened on multiple-thread accessing the same object concurrently.
somewhere in project
public static class Config{
public static Dictionary<string,string> Application = new Dictionary<string,string>();
}
elsewhere
Config.Application["froop"] = "noodle";
of course you will have to deal with race conditions, etc
First of all thank you all for finding some time to help me. I took #pm100's solution and made a slight modification to suit my purpose. I could not use it directly as I am using SonarLint, and it had some issues, so I used a KeyValuePair instead of Dictionary like this:
public static class GlobalData
{
public static KeyValuePair<string,object> Application { get; set; }
}
and I used it in my code like:
string value = GlobalData.Application.Value
and luckily it works without any issue.
Currently, I am using strings to define and consume routes, roles, policies, etc. It is easy to misspell or get the string values wrong, as they are not part of the IDE auto-completion and type checking.
Is there a way to utilize some kind of references or symbols in ASP.NET Core 3.1? Maybe through configuration providers and DI?
What I would like to see is to define these string configuration values once somewhere, and then reference them in various parts of the application?
Why not use constants classes?
public static class RoutingConstants
{
public const string Route1 = "route1";
...
}
And the same thing for any other need
You could then access the constant everywhere like this RoutingConstants.Route1
Authorize with roles:
You can refactor the roles into constants and consume them like this:
public class StaticRoles
{
public const string A = "A";
public const string B = "B";
public const string C = "C";
public const string ABC = "A, B, C";
}
Use these constants like this:
[Authorize(Roles = StaticRoles.ABC)]
[Route("foo")]
public IActionResult Foo()
Consuming routes in views:
When generating links, you can use tag helpers for links which automatically read the Route attribute from the controller method:
<a asp-controller="#nameof(HomeController).Replace("Controller", string.Empty)" asp-action="#nameof(HomeController.Foo)">Foo</a>
You should refactor .Replace("Controller", string.Empty) into a String extension method to reduce code bloat.
Consuming routes in code:
If you want to have the same functionality as the tag helpers in code, you can use the LinkGenerator class which is automatically injected
Use dependency injection to get the reference to the LinkGenerator
public class HomeController : Controller
{
private readonly LinkGenerator linkGenerator;
public HomeController(LinkGenerator linkGenerator)
{
this.linkGenerator = linkGenerator;
}
// ..
}
Inside HomeController, you can then use
linkGenerator.GetPathByAction(
nameof(HomeController.Index),
nameof(HomeController).Replace("Controller", string.Empty))
};
GetPathByAction has a third parameter when the route has parameters as part of the URL:
linkGenerator.GetPathByAction(
nameof(HomeController.Index),
nameof(HomeController).Replace("Controller", string.Empty),
values: new { version = user.Version})
};
I'm making an application that uses an external API. But I don't want my application to be dependant on the API. So I have been reading about how to achieve this. I read that the thing I want is loose coupling. I want to loosely couple my class that uses the external API from the rest of my application. My question is how do I achieve this. If read about different design patterns, I can't find one that helps with my problem.
public class GoogleCalendarService
{
private const string CalendarId = ".....";
private CalendarService Authenticate(string calendarId)
{
...
}
public void Create(Booking newBooking, string userId)
{
...
InsertEvent(newEvent, userId);
}
private void Insert(Event newEvent, string userId)
{
call authenticate account
....
}
public List<Booking> GetEvents()
{
call authenticate account
...
}
}
Above is my code for the class that uses the external API. In the rest of my application I use this class the following way:
public class MyApplication
{
private void MyFunction()
{
GoogleCalendarService googleCalendarService = new GoogleCalendarService();
googleCalendarService.CreateEvent(..., ...)
}
}
I do this on multiple places in my application. So my question is: How can I loosely couple the API class from the rest?
Edit: I probably want a general calendar service interface that makes it easier to replace the google calendar service with an other calendar service when needed.
that makes it easier to replace the google calendar service with an other calendar service
The main pattern you will want to look at is Adapter. But you would want to use that in combination with Dependency Injection.
The DI first:
public class MyApplication
{
// constructor injection
private IGeneralCalendarService _calendarService;
public MyApplication(IGeneralCalendarService calendarService)
{
_calendarService = calendarService;
}
private void MyFunction()
{
_calendarService.CreateEvent(..., ...)
}
}
And the Adapter would look something like
public class GoogleCalendarServiceAdapter : IGeneralCalendarService
{
// implement the interface by calliong the Google API.
}
In addition you will need generic classes for Event etc. They belong to the same layer as the interface.
You need to write a wrapper around that API. And rewrite every Output/Input of that API with your wrapper IO. And after that, you can take advantage of Dependancy Injection to use your own code. By this way you can have an abstraction layer around that API
I trying to experiment with Specflow. So I am writing functional tests for a REST API and have created a couple of step definitions, say CreatePersonStepDefinitions and GetPeopleStepDefinition
Those extend CommonStepDefinition, which provides things like:
[Given(#"a valid API key is given")]
public void AValidApiKeyIsGiven()
{
ApiKey = "Some Api Key";
}
[Then(#"the response HTTP code should be (.*)")]
public void ThenTheStatusCodeShouldBe(int statusCode)
{
Assert.AreEqual (statusCode, (int)Response.StatusCode);
}
This is to be able to run scenarios like
Given I am retrieving all people
And an invalid API key is given
When I make the call
Then the response HTTP code should be 200
And the API response code is 104
And the API call didn't take more than 200 milliseconds
So there are several common steps between step definitions. I understand that I cannot do this as Steps are global. What I wanted to ask is whats the best way (i.e. best practise) to achieve this without duplicating the same steps in every step definition.
Thanks
Because steps are global you don't need to duplicate them in every step definition, you can just use them in ALL features, and specflow will call them.
If your real question is how do I share the ApiKey and Response between my features steps and my common steps there are a few ways but what I would recommend is to use the context injection approqach from the link. I would create context objects and pass these to your step classes. Specflow has a simple DI framework which will do this automatically (most of the time) for you.
I would create something like this:
public class SecurityContext
{
public string ApiKey {get;set;}
}
public class ResponseContext
{
public IHttpResponse Response{get;set;}
}
[Binding]
public class CommonSteps
{
private SecurityContext securityContext;
private ResponseContext responseContext;
public CommonSteps(SecurityContext securityContext,ResponseContext responseContext)
{
this.securityContext = securityContext;
this.responseContext = responseContext;
}
[Given(#"a valid API key is given")]
public void AValidApiKeyIsGiven()
{
securityContext.ApiKey = "Some Api Key";
}
[Then(#"the response HTTP code should be (.*)")]
public void ThenTheStatusCodeShouldBe(int statusCode)
{
Assert.AreEqual (statusCode, (int)responseContext.Response.StatusCode);
}
}
public class MyFeatureSteps
{
private SecurityContext securityContext;
private ResponseContext responseContext;
public MyFeatureSteps(SecurityContext securityContext,ResponseContext responseContext)
{
this.securityContext = securityContext;
this.responseContext = responseContext;
}
///Then in your feature steps you can use the Api key you set and set the response
}
you might even consider not having Common steps as this get just be a big bucket for everything that is not feature specific, but what we usually do is to break the step classes into something like SecuritySteps which would just take the SecurityContext and ResponseSteps which would just take the ResponseContext
I'm having a problem getting my global variables to work on my client application.
In the web service, I have the following code:
public class MyWebService: System.Web.Services.WebService
{
public static string test = String.Empty;
....
On my client side I have this code:
MyService.MyWebService client = new MyService.MyWebService()
{
client.test="test";
};
On the client side I'm receiving
"MyWebService does not contain a definition for test...etc";
Can you use global variables within a web service? Any help would be appreciated.
Thanks!
You'll have to expose getter (and or setter) in webservice in order to be visible for client. i.e:
public class MyWebService: System.Web.Services.WebService
{
public static string test = String.Empty;
public string GetTest() {
return test;
}
public void SetTest(string test) {
MyWebService.test = test;
}
}
Also read some topic on thread-safety, if you're planning to have more clients simultaneously.
Even though it may look like you're actually using classes when invoking web services, you're not. Web services do not know the concept of variables. All you can do is invoke methods.