Calling web api in c# - c#

I am trying to call my webapi locally. This is my postman url and it work great. http://localhost:8080/api/V1/Students
When calling from MVC application I get an exception 404 not found.
This is my student controller
var url = "/Students";
string test = ApiHelper.ApiClient.BaseAddress + url;
using (HttpResponseMessage response = await ApiHelper.ApiClient.GetAsync(url))
{
if (response.IsSuccessStatusCode)
{
listStudent = await response.Content.ReadAsAsync<List<StudentModel>>();
}
else
{
throw new Exception(response.ReasonPhrase);
}
}
Notice: test actually return the url "http://localhost:8080/api/V1/Students". Witch his good.
And this is my ApiHelper code.
public class ApiHelper
{
public static HttpClient ApiClient { get; set; }
public static void InitializeClient()
{
string ApiBaseUrl = ConfigurationManager.AppSettings["ApiUrl"];
ApiClient = new HttpClient();
ApiClient.BaseAddress = new Uri(ApiBaseUrl);
ApiClient.DefaultRequestHeaders.Accept.Clear();
ApiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
}
When I debug it I found that on my response the Request URI
RequestUri {http://localhost:8080/Student}
This is where my api location is called
<appSettings>
<add key="ApiUrl" value="http://localhost:8080/api/V1" />
</appSettings>
What I am doing wrong in trying to call the local api?

api/v1 is a route prefix. Decorate your BaseAddress controller with this route prefix and tray again. Like so:
[RoutePrefix("api/V1")]
public class ProductController : Controller
{

Related

Add multiple tokens into DefaultRequestHeaders.Authorization in HttpClient

The API I'm calling from my ASP.NET Web API app requires two tokens i.e. accessToken and userToken.
The following code is not working because it takes only the second token, not both. Looks like the second line is over-writing the first one.
How do I add multiple tokens to my request header?
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("APIAccessToken", "token1");
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("UserToken", "token2");
UPDATE:
Here's the way I set this up and it's not working. Basically, my API calls seem to go nowhere. I get no errors. Just no response.
First, I have the HttpClientAccessor that looks like this:
public static class HttpClientAccessor
{
private static Lazy<HttpClient> client = new Lazy<HttpClient>(() => new HttpClient());
public static HttpClient HttpClient
{
get
{
client.Value.BaseAddress = new Uri("https://api.someurl.com");
client.Value.DefaultRequestHeaders.Accept.Clear();
client.Value.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.Value.DefaultRequestHeaders.TryAddWithoutValidation("APIAccessToken", "token1");
client.Value.DefaultRequestHeaders.TryAddWithoutValidation("UserToken", "token2");
return client.Value;
}
}
}
I then have my ApiClient that will perform my API calls which looks like this:
public class MyApiClient
{
HttpClient _client;
public MyApiClient()
{
_client = HttpClientAccessor.HttpClient;
}
public async Task Get()
{
try
{
HttpResponseMessage response = await _client.GetAsync("/myendpoint"); // This is where it gets lost
var data = await response.Content.ReadAsStringAsync();
}
catch(Exception e)
{
var error = e.Message;
}
}
}
This is my controller action:
public class MyController : Controller
{
private readonly MyApiClient _client;
public MyController()
{
_client = new MyApiClient();
}
public IActionResult SomeAction()
{
_client.Get().Wait();
}
}
You are confusing the standard authorization header with custom headers
According to the linked documentation
Request Header
Add the generated tokens to the request headers "APIAccessToken" and "UserToken"
Example Request
APIAccessToken: zjhVgRIvcZItU8sCNjLn+0V56bJR8UOKOTDYeLTa43eQX9eynX90QntWtINDjLaRjAyOPgrWdrGK12xPaOdDZQ==
UserToken: 5sb8Wf94B0g3n4RGOqkBdPfX+wr2pmBTegIK73S3h7uL8EzU6cjsnJ0+B6vt5iqn0q+jkZgN+gMRU4Y5+2AaXw==
To get headers like above, add them to the client like below
_client.DefaultRequestHeaders.TryAddWithoutValidation("APIAccessToken", "token1");
_client.DefaultRequestHeaders.TryAddWithoutValidation("UserToken", "token2");
Based on shown update, the client is adding the headers every time the client is called. This should be in the value factory of the lazy client.
public static class HttpClientAccessor {
public static Func<HttpClient> ValueFactory = () => {
var client = new HttpClient();
client.BaseAddress = new Uri("https://someApiUrl");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.TryAddWithoutValidation("APIAccessToken", "token1");
client.DefaultRequestHeaders.TryAddWithoutValidation("UserToken", "token2");
return client;
};
private static Lazy<HttpClient> client = new Lazy<HttpClient>(ValueFactory);
public static HttpClient HttpClient {
get {
return client.Value;
}
}
}
The controller action also needs to be refactored to avoid deadlocks because of the mixing of async and blocking calls like .Wait() or .Result.
public class MyController : Controller {
private readonly MyApiClient _client;
public MyController() {
_client = new MyApiClient();
}
public async Task<IActionResult> SomeAction() {
await _client.Get();
//... code removed for brevity
}
}

Displaying result in console instead of web page

The project I have created, is an ASP.NET Web API which communicates with a Java Web Service through HttpClient. When I run the Java Web Service, I get the result {"id":2,"content":"Hello, World!"}. When I run the ASP.NET Web API, The ASP.NET Web API gets result from the Java Web Service and displays result as "{\"id\":2,\"content\":\"Hello, World!\"}" in a web page.
How do I display the result in console, which means I create a console application and put in these codes and I want the result to come out in a console and not web page. How do I do that? What are the codes that has to be modified? Someone please kindly do help me thank you so much.
Here are my ASP.NET Codes that I have done so far:
ClientController.cs
public class ClientController : ApiController
{
private ServerClient serverClient = new ServerClient();
public async Task<IHttpActionResult> GET()
{
try
{
var result = await serverClient.content();
return Ok(result);
}
catch (Exception e)
{
var result = "Server is not running";
return Ok(new { ErrorMessage = result });
}
}
}
ServerClient.cs
public class ServerClient
{
private static HttpClient client;
private static string BASE_URL = "http://localhost:8080/";
static ServerClient()
{
client = new HttpClient();
client.BaseAddress = new Uri(BASE_URL);
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<string> content()
{
var endpoint = string.Format("greeting");
var response = await client.GetAsync(endpoint);
return await response.Content.ReadAsStringAsync();
}
}
WebApiConfig.cs
config.Routes.MapHttpRoute(
name: "TestClient",
routeTemplate: "api/testclient",
defaults: new { actcion = "Get", controller = "Client" }
);
static void Main(string[] args)
{
var result = serverClient.content().Result;
Console.WriteLine(result);
}
Please note that using Result or Wait() in async programming might cause deadlock

Calling remote web api from mvc controller

What is the preferred way for handling web api endpoints for each controller?
For example, my MVC controller will be calling different endpoints.
These are the only ones for now, but it could change.
Also, I will be developing this locally and and deploying to development server.
http://localhost:42769/api/categories/1/products
http://localhost:42769/api/products/
public class ProductsController : Controller
{
HttpClient client;
string url = "http://localhost:42769/api/categories/1/products"; //api/categories/{categoryId}/products
public ProductsController()
{
client = new HttpClient();
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
// GET: Products
public async Task<ActionResult> ProductsByCategory()
{
HttpResponseMessage responseMessage = await client.GetAsync(url);
if (responseMessage.IsSuccessStatusCode)
{
var responseData = responseMessage.Content.ReadAsStringAsync().Result;
var products = JsonConvert.DeserializeObject<List<GetProductsByCategoryID>>(responseData);
return PartialView(products);
}
return View("Error");
}
}
Not sure I understand you question or problem, but I would create a wrapper class for the service and then have different methods for each resource that you need to call. Always think SOLID.
Example (written by hand)
public class Client
{
private Uri baseAddress;
public Client(Uri baseAddress)
{
this.baseAddress = baseAddress;
}
public IEnumerable<Products> GetProductsFromCategory(int categoryId)
{
return Get<IEnumerable<Product>>($"api/categories/{categoryId}/products");
}
public IEnumerable<Products> GetAllProducts()
{
return Get<IEnumerable<Product>>($"api/products");
}
private T Get<T>(string query)
{
using(var httpClient = new HttpClient())
{
httpClient.BaseAddress = baseAddress;
var response= httpClient.Get(query).Result;
return response.Content.ReadAsAsync<T>().Result;
}
}
}

Call Web API from MVC Controller using the same HttpClient

I have an MVC5 project, from the MVC controller I need to call the Web API method. The Web API uses token based authentication, so I have to pass the token for each call. I am using the code below to pass the token in the HTTP header:
HttpClient httpClient = new HttpClient();
string baseUrl = "http://localhost:60477/";
dynamic token = Session["token"];
if (token.AccessToken != null)
{
httpClient.DefaultRequestHeaders.Add("Authorization", String.Format("Bearer {0}", token.AccessToken));
}
There are multiple action methods in my controller, and I want to use a single HttpClient and headers, added in one place, instead of adding a header in each and every action method.
Where can I place the HttpClient headers registration code in the MVC application, so it can be common to all controllers? That means I don't want to repeat code, like adding the token in each and every action method. How can I do that?
Public ActionResult Postuser(UserModel user)
{
// post code
}
Public ActionResult getuser(UserModel user)
{
HttpResponseMessage response = httpClient.GetAsync(baseUrl + "api/Admin/GetStates").Result;
if (response.IsSuccessStatusCode)
{
string stateInfo = response.Content.ReadAsStringAsync().Result;
}
}
Public ActionResult PostRoles(RoleModel role)
{
// post roles code
}
You can try creating a small helper class for creating your httpclient object. Something like
public class HttpClientHelper
{
public static HttpClient GetHttpClient()
{
var MyHttpClient = new HttpClient();
dynamic _token = HttpContext.Current.Session["token"];
if (_token == null) throw new ArgumentNullException(nameof(_token));
MyHttpClient.DefaultRequestHeaders.Add("Authorization", String.Format("Bearer {0}", _token.AccessToken));
return MyHttpClient;
}
}
and then call it in your controllers as
public ActionResult getuser(UserModel user)
{
var httpClient = HttpClientHelper.GetHttpClient();
HttpResponseMessage response = httpClient.GetAsync(baseUrl + "api/Admin/GetStates").Result;
if (response.IsSuccessStatusCode)
{
string stateInfo = response.Content.ReadAsStringAsync().Result;
}
}
It is better to adhere to the Single Responsibility Principle and extract the interaction with another service in a it's own class, e.g.
public class ServiceClient : IServiceClient
{
private HttpClient m_Client;
public ServiceClient
{
m_Client = new HttpClient();
// Initialize the client as you need here
}
public void CallSomeMethod()
{
// Call method on the client
}
}
Then you inject the IServiceClient in your controller and just call it's methods. If you do not use injection (which I advise you do) you can just create a new instance in the controller's constructor.
You can try using an action filter in your controller. Try adding an override that looks something like this-
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
// some condition code to target a specific method in the controller
// Example
if (filterContext.ActionDescriptor.ActionName == "getuser") // <-- your method
{
// put your token based authentication code here
}
base.OnActionExecuting(filterContext);
}
The OnActionExecuting method is at the controller scope so you can have different logic for different controllers.
There's also an OnActionExecuted method override if you want to run code after your action method.
------edit--------------
As far as where to place your HttpClient code snippet, you can try this-
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpClient httpClient = new HttpClient();
string baseUrl = "http://localhost:60477/";
dynamic token = Session["token"];
if (token.AccessToken != null)
{
httpClient.DefaultRequestHeaders.Add(
"Authorization",
string.Format("Bearer {0}", token.AccessToken)
);
httpClient.BaseAddress = new Uri(baseUrl);
}
if(filterContext.ActionParameters.ContainsKey("httpClient"))
{
filterContext.ActionParameters["httpClient"] = httpClient;
}
else
{
// error
}
base.OnActionExecuting(filterContext);
}
So the HttpClient object along with the assignment of your baseUrl is established in OnActionExecuting. This code will run before any method returning a ActionResult in the controller you are refactoring. If you want to target some and not all methods, see the first example of OnActionExecuting above.
public ActionResult getuser(UserModel user, HttpClient httpClient)
{
HttpResponseMessage response = httpClient.GetAsync("api/Admin/GetStates").Result;
if(response.IsSuccessStatusCode)
{
string stateInfo = response.Content.ReadAsStringAsync().Result;
}
// the rest of your code for getuser..
return View();
}
Now your getuser method has an extra parameter ( HttpClient httpClient ).
why don't you move the code in Global asax or create custom Atribute?
here is one good link:
http://www.diaryofaninja.com/blog/2011/07/24/writing-your-own-custom-aspnet-mvc-authorize-attributes

Posting data to Web API using custom Authentication

This is a follow-up on an earlier question regarding using HttpClient with Web API performing authentication using a custom Message Handler.
I can request data from the server using the provided solution, but now I am having trouble posting JSON data to the server. Whenever I try posting data to the Web API I am returned an Internal Server Error response code.
Here is the code on the client side:
using (var httpClient = new HttpClient())
{
var request = new HttpRequestMessage();
request.Headers.Add("X-Token", UserSession.GlobalInstance.SecurityToken);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Method = HttpMethod.Post;
request.RequestUri = new Uri(_apiBaseAddress + "api/User");
request.Content = new ObjectContent<UserDTO>(userDTO, new JsonMediaTypeFormatter());
var response = httpClient.SendAsync(request).Result;
if (response.IsSuccessStatusCode)
{
// handle result code
}
throw new Exception(String.Format("Server generated error response: {0}", response.StatusCode));
}
The declaration for the controller method:
public class UserController : ApiController
{
public long Post(UserDTO userDTO)
{
// create user and return custom result
// code (e.g. success, duplicate email, etc...)
}
}
(I've also added [FromBody] to the method parameter, but end up with the same result).
A snapshot of the code for my message handler and routing configuration can be found here.
Your code works as expected...
The server side.
Create a console application and run NuGet
Install-Package Microsoft.AspNet.WebApi.OwinSelfHost
Program.cs
internal class Program
{
private static IDisposable _server;
private static void Main(string[] args)
{
_server = WebApp.Start<Startup>("http://localhost:12345");
Console.ReadLine();
_server.Dispose();
}
}
Startup.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseWebApi(config);
}
}
WebApiConfig.cs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var userTokenInspector = new UserTokenInspector {InnerHandler = new HttpControllerDispatcher(config)};
config.Routes.MapHttpRoute(
"UserAuthenticationApi",
"api/{controller}/Authenticate",
new {controller = "User", action = "Authenticate"},
null
);
config.Routes.MapHttpRoute(
"DefaultApi",
"api/{controller}/{id}",
new {id = RouteParameter.Optional},
null,
userTokenInspector
);
}
}
UserTokenInspector.cs
public class UserTokenInspector : DelegatingHandler {
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken) {
const string TOKEN_NAME = "X-Token";
if (!request.Headers.Contains(TOKEN_NAME)) {
return Task.FromResult(request.CreateErrorResponse(HttpStatusCode.Unauthorized,
"Request is missing authorization token."));
}
try {
//var token = UserToken.Decrypt(request.Headers.GetValues(TOKEN_NAME).First());
// validate token
// ...
// ...
Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity("alex"), new string[] { });
}
catch {
return Task.FromResult(request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Invalid token."));
}
return base.SendAsync(request, cancellationToken);
}
}
UserController.cs
public class UserController : ApiController
{
public long Post(UserDTO userDTO)
{
// create user and return custom result
// code (e.g. success, duplicate email, etc...)
return 1;
}
}
UserDto.cs
public class UserDTO
{
public string Username { get; set; }
}
ValuesController.cs
public class ValuesController : ApiController
{
public HttpResponseMessage Get()
{
return Request.CreateResponse(HttpStatusCode.OK, "yay");
}
}
The Client... create a Console application and run NuGet:
Install-Package Microsoft.AspNet.WebApi.Client
Program.cs
internal class Program
{
private static void Main(string[] args)
{
var request = new HttpRequestMessage();
request.Headers.Add("X-Token", "token");
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Method = HttpMethod.Post;
var baseAddress = "http://localhost:12345/";
request.RequestUri = new Uri(baseAddress + "api/User");
var userDto = new UserDTO() {Username = "Alex"};
request.Content = new ObjectContent<UserDTO>(userDto, new JsonMediaTypeFormatter());
var httpClient = new HttpClient();
var response = httpClient.SendAsync(request).Result;
if (response.IsSuccessStatusCode)
{
// handle result code
Console.WriteLine(response.StatusCode);
Console.ReadLine();
}
}
}

Categories

Resources