Given a controller Proxy and an action of GetInformation. I want to be able to call the method GetInformation of the Users controller. Both the WebAPI controllers are in the same project but direct calls like
var controller = new UsersController();
return controller.GetInformation(request);
Doesn't work.
The signature is:
public HttpResponseMessage GetInformation(InformationRequest request)
I do not want to do a full redirect response as I do not want the UserController route exposed externally. This needs to be an internal only call.
For those wanting to solve this API to API method in different controllers, we have found a solution that works. The initial attempt was close, just missing a few things.
var controller = new UserAccountController
{
Request = new HttpRequestMessage(HttpMethod.Post, Request.RequestUri.AbsoluteUri.Replace("/current/route", "/route/to_call"))
};
controller.Request.Properties[HttpPropertyKeys.HttpConfigurationKey] = new HttpConfiguration();
return controller.GetInformation(request);
In doing this it allows construction of the target controller and direct invocation of the method desired. The biggest complexity here is the Uri adjustment.
You should do something like this in your UsersController
public HttpResponseMessage GetInformation(InformationRequest request)
{
HttpResponseMessage resp ;
resp = UserBusinessLogic.GetInformation(request) ;
return resp ;
}
and from your ProxyController you can resuse that "UserBusinessLogic" method to obtain the same information using the same code snippet.
Another way can be:
IQueryable<Users> GetInformation()
without using the IHttpActionResult return type. Your method will still remain an Http GET method and then call it in the same way as you call any class method.
Related
Currently, I have two services running at different endpoints. For example (this is not my real scenario):
StudentService
CheckHomeWorkService
CheckHomeWorkService can be used from many services (For example TeacherService, WorkerService). It has one controller with CheckHomeWork action. It has some parameters:
HomeWorkNumber (int)
ProvidedSolution (string).
It will return success or failed.
Now, In my StudentService, I have a controller with SubmitHomeWork Action. It needs to check homework using CHeckHomeWorkService and save results to a database. How can I implement this?
I was using Ocelot Api GateWay but it can 'redirect' to another service and I need to save the result of the response to the database
As suggested in the comments, you can use HttpClient to call the other APIs. However, if you want a more safe and performant solution, you can use also the HttpClientFactory.
see this why to use it
and see the official docu
After your comment you say that you have separate WEB API services
in this case you can do this service to retrieve the result :
public async Task<List<HomeWorkModel>> CheckHomeWorkService(int
homeWorkNumber, string providedSolution)
{
using (var httpClient = new HttpClient())
{
using (var response = await
httpClient.GetAsync(Constants.ApiBaseUrl + "/CheckHomeWork?n=" +
homeWorkNumber + "&sol=" + providedSolution))
{
if (response.StatusCode ==
System.Net.HttpStatusCode.OK)
{
string apiResponse = await
response.Content.ReadAsStringAsync();
return
JsonConvert.DeserializeObject<List<HomeWorkModel>>(apiResponse);
}
else
{
return null;
}
}
}
}
public class HomeworkModel
{
Public bool Result {get; set;}
}
whereas :
"Constants.ApiBaseUrl" is http address for base Url of another API
But in case of the same API you will use old solution :
you can pass "CHeckHomeWorkService" in your controller constructor ("Dependency Injection")
and call service methods as you like
I have a method in Api as follows
[HttpPut]
[Route("UpdateTeacher")]
public IHttpActionResult UpdateTeacher(BusinessLayerTeacher Obj)
{
try
{
BusinessLayerTeacher obj = new BusinessLayerTeacher ();
string status = BusinessLayerObject.UpdateTeacher(TeacherObj);
return Ok(status);
}
catch
{
return NotFound();
}
}
Now in post man i am sending the put request to update the teacher object.
It is not triggering this updateTeacher() method.
You are instantiating a new BusinessLayerTeacher object inside the method, which looks suspect when you are already passing in BusinessLayerTeacher as a parameter.
Maybe the route mapping isn't working because you're not passing in the right data in the request body.
Maybe you should be using TeacherObj as the parameter type?
Have a review and give that a try, good luck :-)
So I'm having a troubles getting the route to work properly after the messagehandler has finished.
Error that shows up are:
No HTTP resource was found that matches the request URI
this is what I got so far:
http://localhost:51077/api/v1/project/getprojects?apikey=123456
// all actions under /project routes require authentication
config.Routes.MapHttpRoute(
"ProjectApi",
"api/v1/{controller}/{action}/{apikey}",
new { apikey = RouteParameter.Optional },
null,
HttpClientFactory.CreatePipeline(
new HttpControllerDispatcher(config),
new DelegatingHandler[]{new BasicAuthHandler(config)}));
// all routes requires an api key
config.MessageHandlers.Add(new ApiKeyHandler());
config.MapHttpAttributeRoutes();
[RoutePrefix("api/v1/ProjectController")]
public class ProjectController : BaseApiController
{
[HttpGet]
[Route("getprojects")]
public HttpResponseMessage GetProjects()
{
HttpResponseMessage resp = new HttpResponseMessage(HttpStatusCode.OK);
if(User.Identity.IsAuthenticated)
{
}
return resp;
}
}
So, all calls will first be checked if they have an ApiKey included to be able to connect (ApiKeyHandler) Then a popup appears and asks for username and password(BasicAuthHandler). If the log in is a success then it should be forwarded to the getprojects method under /project...
ApiKey is checked, username/password popup appears and is granted but then the error above comes and the route seems to be to invalid. I've tried different ways to get this to work but it seems I'm missing something here.
PROBLEM SOLVED
Just comment this line out and it works
[Route("getprojects")] // <--- COMMENT/REMOVE THIS LINE
Any ideas to why this was causing the problem?
Your issue doesn't replicate in my test that I tried at my end. It seems you have different names given to your controller in your RoutePrefix attribute. According to the request Url given:
http://localhost:51077/api/v1/project/getprojects?apikey=123456
RoutePrefix attibute on ProjectController class should look like:
[RoutePrefix("api/v1/Project")]
I have the following namespace for the web service and I can see lots of functions I can access...
using MyService.api;
public class HomeController : Controller
{
public ActionResult Index()
{
//What needs to go here?
// LoginRequest and Response are types from the web service reference
LoginRequest loginRequest = new LoginRequest();
loginRequest.user = "blah";
loginRequest.password = "abc1234";
LoginResponse loginResponse = new LoginResponse();
string sessionID = loginResponseSession.session.sessionId; // This has nothing in it
return View("Index", sessionID );
}
...
the api exposes all of these methods, things like:
MachineRequest machineRequest = new MachineRequest();
string[] machines = machineRequest.machines;
But ofcourse when I call that, it does not magically go and collect machines from the url.
How do I make and respond to the requests? What is the Service reference actually for?
Your question is a bit unclear. If you've generated a WCF service reference, you can use the "proxy" or "client" like this:
var client = new MyService.api.ApiReferenceClient();
var loginResponse = client.LoginRequest(loginRequest);
That will perform the SOAP call (or whatever binding is being used).
I am using WEB API 2.0 for REST Service development and I need to pass a parameter from request header to the API controller action method. How can I?
By default API controller is reading the parameters from request body.
How can I make it read parameter from request header?
[HttpPost]
[Route("abc")]
public IHttpActionResult abcMethod(string s)
{
//some code
}
I want the above abcMethod to read it's parameter from request header.
Pls suggest.
How about this...
IEnumerable<string> headerValues = request.Headers.GetValues("MyCustomID");
var id = headerValues.FirstOrDefault();
I'm still new to the Web API 2, but I usually do
string variale = this.Request.Headers.GetValues("HeaderParameter").First();
Any of the FirstOrDefault, Single, SingleOrDefault() or anything of the like will work.
Also, Lambda works as well:
string variable = this.Request.Headers.First(header => header.Key == "Parameter").Value.FirstOrDefault();