I use HttpClient with ASP to consume services in a remote database
In my ASP controller (Collaborateur), I have the following code:
public Boolean UpdateCollaborateur(Collaborateur collaborateur) {
using (var client = new HttpClient()) {
(.......)
}
return true;
}
Then in my angular service, i have the following call:
.factory('UpdateCollaborateur', function ($http) {
var fac = {};
fac.Update = function (collaborateur) {
return $http.put('/Collaborateur/UpdateCollaborateur/'+collaborateur);
};
return fac;
})
By putting a breakpoint , why i can not access in my function UpdateCollaborateur after executing my method in my controller angularjs?
Thanks for your help
I may be wrong but shouldn't it be:
return $http.put('/Collaborateur/UpdateCollaborateur/', collaborateur);
You have a + instead of a ,.
You also likely need the [HttpPut] attribute on the method.
NOTE: HTTP PUT not allowed in ASP.NET Web API
Related
I'm trying to consume my asp.net web api in my asp.net core mvc web app which are on the same solution. I configured the solution for multi-project start and they start both.
next I tried to consume the API in the Web part but I'm getting the following error.
InvalidOperationException: A suitable constructor for type 'ProjectName.Web.Services.Interfaces.IAdminService' could not be located. Ensure the type is concrete and all parameters of a public constructor are either registered as services or passed as arguments. Also ensure no extraneous arguments are provided.
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.FindApplicableConstructor(Type instanceType, Type[] argumentTypes, out ConstructorInfo matchingConstructor, out Nullable[] matchingParameterMap)
Here is the complete Stack trace
The Projects are structure like this
SolutionName:
Name.API
Name.Web
each with its own respective structure
This is my Helper Class
public static class HttpClientExtensions
{
public static async Task<T> ReadContentAsync<T>(this HttpResponseMessage response)
{
//if (response.IsSuccessStatusCode == false) return StatusCodes = 300;
//throw new ApplicationException($"Something went wrong calling the API: {response.ReasonPhrase}");
var dataAsString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var result = JsonSerializer.Deserialize<T>(
dataAsString, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
return result;
}
}
The IAdmin Inter Face
Task<IEnumerable<Admins>> GetAllAdmins();
The AdminService(Implementation)
private readonly HttpClient _client;
public const string BasePath = "api/Admins";
public AdminService(HttpClient client)
{
_client = client; // ?? throw new ArgumentNullException(nameof(client));
}
public async Task<IEnumerable<Admins>> GetAllAdmins()
{
var response = await _client.GetAsync(BasePath);
return await response.ReadContentAsync<List<Admins>>();
}
Admins Controller
private readonly IAdminService _adminService;
public AdminController(IAdminService adminService)
{
_adminService = adminService;
}
public async Task<IActionResult> Index()
{
var adminsList = await _adminService.GetAllAdmins();
if(adminsList == null)
{
return new JsonResult("There are now Admins");
}
return View(adminsList);
}
Program.cs
builder.Services.AddControllersWithViews();
builder.Services.AddHttpClient<IAdminService, IAdminService>(c =>
c.BaseAddress = new Uri("https://localhost:<port-Num>/"));
var app = builder.Build();
What Could I be doing wrong???
I'm using .NET 6 adn both Projects are in the same solution
NB My end points are working fine, I test them using Postman.
It is failing because DI cannot instantiate your AdminService with parameterized constructor. This is possibly a duplicate of Combining DI with constructor parameters? .
Essentially, you should avoid parameterized constructor injection where possible. Either control it through configuration or have the configuration loaded through common infrastructure such as host configuration.
According to your codes, I found you put two interface inside the AddHttpClient method which caused the issue.
I suggest you could modify it like this and then it will work well.
builder.Services.AddHttpClient<IAdminService, AdminService>(c =>
c.BaseAddress = new Uri("https://localhost:3333/"));
i have a xamarin app that is trying to talk to use SignalR in Azure functions.
i have 2 azure functions as per the documentation.
public static class NegotiateFunction
{
[FunctionName("negotiate")]
public static SignalRConnectionInfo GetSignalRInfo(
[HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req,
[SignalRConnectionInfo(HubName = "chat")] SignalRConnectionInfo connectionInfo)
//, UserId = "{headers.x-ms-client-principal-id}"
{
return connectionInfo;
}
}
and
public static class SendMessageFunction
{
[FunctionName("Send")]
public static Task SendMessage(
[HttpTrigger(AuthorizationLevel.Anonymous, "post")]object message,
[SignalR(HubName = "chat")]IAsyncCollector<SignalRMessage> signalRMessages)
{
// var chatObj = (ChatObject)(message);
return signalRMessages.AddAsync(
new SignalRMessage
{
// the message will only be sent to this user ID
// UserId = chatObj.ReciversId,
Target = "Send",
Arguments = new[] { message }
});
}
}
in my xamarin client i am connecting like this.
try
{
_connection = new HubConnectionBuilder()
.WithUrl("http://192.168.1.66:7071/api")
.Build();
_connection.On<string>("Send", (message) =>
{
AppendMessage(message);
});
await _connection.StartAsync();
}
I send message using this code in one of the pages of Xamarin app page.
try
{
await _connection.SendAsync("Send", MessageEntry.Text);
MessageEntry.Text = "";
}
connection code works it hits "negotiate" function properly but when i call SendAsync it does not hit break-point in [FunctionName("Send")] and nothing happens. It doesn't give me any exception as well.
local settings are like this
Update
i also tried Invoke. it didnt worked.
Should i try making a POST call to [FunctionName("Send")] ?
The way SignalR SaaS works in Functions is slightly different to using the NuGet package in a .NET Application.
You can't invoke a function using the SignalR library, as you can see on the attribute in your function, it's expecting a Http trigger so you have to do a POST to this endpoint instead of invoking it as you normally would.
[HttpTrigger(AuthorizationLevel.Anonymous, "post")]
You still want to listen to the Send target as normal.
I am using Angular 2 in order to send http requests to the server.
The server is running with ASP.Net.
My API:
public class LagerController : ApiController
{
public IHttpActionResult RepHistorie(string vnr, string lagerort)
{
...
}
}
So I would call the API with
http://123.456.7.89/api/lager?vnr=W17291092373&lagerort=0382691395
This works fine when using a tool called postman with wich you can test API's.
But when making a post request with Angular 2, it doesn't work.
It says that the HTTP-resource is not found.
Angular 2:
submit() {
var body = 'vnr=W17291092373&lagerort=0382741400';
var link = 'http://123.456.7.89/api/lager';
this.http.post(link, body)
.subscribe(data => {
console.log(data);
}, error => {
console.log("Oooops!");
});
}
It seems like the parameters aren't added correctly.
Edit: Changed tag
This needs clarification, since the API above seems to be a GET Request.
In case it is a POST Request , then you should use the whole URL while running the API
In case you want to submit an object , you should use [FromBody] as a parameter
Example
[HttpPost]
public IHttpActionResult( [FromBody]YourObject item ) {
}
====
Client-side
var postUrl = 'http://123.456.7.89/api/lager?vnr=W17291092373&lagerort=0382691395';
var postObject = {};
http.post(postUrl,postObject)
For GET request where you would like to use QueryString
[HttpGet]
public IHttpActionResult RepHistorie([FromQuery]string vnr,[FromQuery]string lagerort){
...
}
====
// Query string can be built using RequestOptionsArgs as well
var builtUrl = 'http://123.456.7.89/api/lager?vnr=W17291092373&lagerort=0382691395';
http.get(builtUrl)
Alternative way is to
var getUrl = 'http://webapi/api/lager';
var requestOptions = {};
http.get(getUrl,requestOptions);
Reference:
Angular HTTP: https://angular.io/api/http/Http , check get() and post() methods
RequestOptionsArgs : https://angular.io/api/http/RequestOptionsArgs
When the user adds a new entry in the client, I need to make a web service call from the server (the client-side code will not have access) and add some additional information to the data stored in MongoDB.
Trying to use the standard Meteor.methods/Meteor.call pattern does not seem to work.
Do I need to listen for the click event on the "Add" button on both the server and the client?
Should I raise a custom event on the client that the server reacts to?
Is there a proper way to make a direct call to a server-side method?
Most importantly, how do I keep TypeScript happy in all of this?
I am new to the TypeScript layer on top of Meteor and it is throwing me for loop. I have been generally following the Angular-Meteor tutorial for 2.0 but this sort of thing is not covered yet.
Yes, you can call directly from the server to the web service in order to receive data. I am not so sure how you did for the Meteor.methods/Meteor.call and say it did not work. But basically, the idea is client will click the button and then button will trigger a method on the server. The server method then will call the web service and return the data.
Some example code could be:
Template['template'].events({
'click .getData': function(event: any) {
Meteor.call('serverMethod', function(err, res) {
if (err) {alert(err);}
else { ... }
)
}
});
The tricky part for new comer when calling the rest is you need to use aysnc calling in order to return the data to client. We normally make helper function for that
public static get(url: string, headers: any): any {
var httpCall = Meteor.wrapAsync(HTTP.call);
var result = httpCall('GET', url, {headers: headers});
if (result.statusCode == 200) {
try {
var res = JSON.parse(result.content);
return res;
} catch(err) {
return result.content;
}
}
return null;
}
And call the helper like this
public static serverMethod(username: string, password: string): any {
var response = RestService.get(query.url, query.header);
return response;
}
This way, the res in the client code above will get the result.
I actually dropped the Angular 2 for the lack of documentation, but stay with Typescript for my system because I can wrap all the meteor call inside the Typescript class, as you can see in my example, serverMethod is in the typescript function format, not in meteor way like Meteor.methods({....}), which is really good for now
Typically, this is a class in my server folder
// server/rest.service.ts
declare var RestService: any;
RestService = class RestService {
methodMap = {
"getFromRest": RestService.get,
"postToRest": RestService.post,
};
constructor() {
var abstractService = new AbstractService();
abstractService.registerMethod(this.getClassName(), this.methodMap);
}
getClassName(): string {
return this.constructor.toString().match(/\w+/g)[1];
}
//------------------------------------------------------------------------------------
// Helper methods
//------------------------------------------------------------------------------------
public static get(url: string, headers: any): any {
var httpCall = Meteor.wrapAsync(HTTP.call);
var result = httpCall('GET', url, {headers: headers});
if (result.statusCode == 200) {
try {
var res = JSON.parse(result.content);
return res;
} catch(err) {
return result.content;
}
}
return null;
}
I have a class to map the typescript service to the meteor method
// server/abstract.service.ts
declare var AbstractService: any;
AbstractService = class AbstractService {
constructor() {}
public registerMethod (scopeName: string, methodMap: {[key:string]:any}) {
var scopeMap: {[key:string]: any} = {};
for (var key in methodMap) {
scopeMap[scopeName + '.' + key] = methodMap[key];
}
Meteor.methods(scopeMap);
}
Using angular2, Meteor and Typescript, what works is to chain the Meteor.methods.
First on the client, in response to a button click
...
Meteor.call('importCsv',id,function(error,result) {
...
In collections/methods folder or similar, I define the method as follows:
Meteor.methods({
'importCsv': function(id) {
console.log('importCsv method on client');
Meteor.call('importCsvServer',id);
}
});
In server/ folder, a file includes the method as follows
Meteor.methods({
'importCsvServer': function(id) {
....
In server/main.ts I import the collections/methods/filename. In client/app.ts I import the same thing. The client Meteor.call successfully calls the first method which then calls the second one in the server/ folder.
My goal is to have a bunch of processing on the server initiated by the client. When I had the function calls in the method defined in collections/methods imported into both the client and server, it resulted in compiler errors.
Angular2-Meteor issue 74
I have a legacy logging DLL that logs errors into a database. Instead of consuming the DLL within each application in our environment, we would like to make web calls to log errors.
I have built up a web.api app that will log errors into a database. When tested with POSTMAN it works as advertised.
I have added a class within a demo MVC app and wired up one of my constructors to execute a log command, but the call not only does not make it to my web.api, but fiddler does not show a call even being made.
Any input on making this actually run would be greatly appreciated.
Here's my code:
Logging Utility Called within Web.API
public class Utilities
{
public void LogException(string exceptionMessage, string stackTrace, string appCode, string runMode, int entityId, int itmsUserID, string updateBy, string path, string method)
{
ErrorLog.Entry _error = new ErrorLog.Entry();
_error.ErrorMessage = exceptionMessage;
_error.StackTrace = stackTrace;
_error.AppCode = appCode;
_error.Path = path;
_error.Method = method;
_error.UpdateBy = updateBy;
_error.RunMode = runMode;
_error.EntityID = entityId;
//_error.Server = server; server will have to be changed to accept a setter
_error.ITMSUserID = CommonFunctions.Get_ITMSUserID(updateBy);
_error.Save();
}
}
Web.API
// POST: api/ErrorLog
public void Post([FromBody]ErrorLogEntryDTO item)
{
var utils = new Utilities();
utils.LogException(item.ErrorMessage, item.StackTrace, item.AppCode, item.RunMode, item.EntityID, item.ITMSUserID, item.UpdateBy, item.Path, item.Method);
}
MVC Controller Code
// GET: BillingRules/Create
public virtual ActionResult CauseHandledError()
{
try
{
throw new Exception("Handled exception test");
}
catch (Exception ex)
{
var utils = new Utilities();
utils.LogException(ex, "system", MVC.BillingRules.Name, MVC.BillingRules.ActionNames.CauseHandledError);
}
return RedirectToAction(MVC.BillingRules.ActionNames.Index, MVC.BillingRules.Name);
}
Utilities Code within MVC App
public void LogException(Exception exception, string updateBy, string path, string method)
{
try
{
var itmsUserID = CommonFunctions.Get_ITMSUserID(updateBy);
var errorDTO = new ErrorLogEntryDTO();
errorDTO.ITMSUserID = itmsUserID;
errorDTO.AppCode = _appCode.Value;
errorDTO.ErrorMessage = exception.Message;
errorDTO.StackTrace = exception.StackTrace;
errorDTO.Path = path;
errorDTO.Method = method;
errorDTO.UpdateBy = updateBy;
var client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:52316");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var result = client.PostAsJsonAsync("api/ErrorLog", errorDTO).Result; //ContinueWith(readTask => client.Dispose()); //
}
catch (Exception ex)
{
var myError = ex;
throw;
}
}
I'm pretty sure calling .Result in this instance does not immediately invoke the PostAsJsonAsync method. Because you're not doing anything with the Result, it never actually executes. Since it doesn't appear you care about the response, you should be able to use:
client.PostAsJsonAsync("api/ErrorLog", errorDTO).Wait();
I think .Result invokes the PostAsJsonAsync call. You are waiting for the respsonse, so the call must be finished after this line. Regardless if you use the Result or not.
You can remove the [FromBody] attribute, because the complex type is per default read from the body.
And I can't reproduce your issue. I've created a new Web API project and a new console project. In the Web API I've changed the post of the valuescontroller to yours.
In the console project I'm yousing your LogException() method from the MVC app.
It hits my web api app.
Are both in the same host or in different hosts?
Edit:
To make your logging async you can use fire-and-forget with Task.Run() but it depends on the application you have. In ASP.Net Task.Run() is an anti-pattern according to Task.Run Etiquette Examples: Don't Use Task.Run in the Implementation.