I'm new to ASP.Net and I'm building a website with Blazor server-side and I'm trying to post a form from the client to a controller like this :
Code for the client (located in /pages) :
private async void LogIn()
{
isSubmitting = true;
var json = JsonConvert.SerializeObject(logInForm);
var data = new StringContent(json, Encoding.UTF8, "application/json");
//The base adress correspond to "https://localhost:port/"
string adress = WebClient.httpClient.BaseAddress + "log_in";
var result = await WebClient.httpClient.PostAsync(adress, data);
isSubmitting = false;
}
Code for the server (located in /controllers) :
public class UserController : Controller
{
private readonly AppDbContext _db;
public UserManager<AppUser> _manager;
public UserController(AppDbContext db, UserManager<AppUser> manager)
{
_db = db;
_manager = manager;
}
[Route("log_in")]
[HttpPost]
private async Task<IActionResult> LogIn([FromBody]LogInForm userForm)
{
var user = new AppUser { UserName = userForm.mail, Email = userForm.mail };
var result = await _manager.CheckPasswordAsync(user, userForm.password);
return null;
}
}
When I execute this code, PostAsync() never redirect to the LogIn() method and return with an HTTP 400 error.
I learned first how to do it with PostJsonAsync() but it was using Blazor WebAssembly, which is in preview so I can't use it in production. I tried to find an answer on Internet first but there is no clear information on how to do it for Blazor server-side.
Any chance I could get a quick and simple explanation on what I'm doing wrong ?
default routing in asp.net is
weburl.com/{controller}/{action}
this would mean the url you're looking for is probably
weburl.com/user/log_in
see : https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-3.0
Related
I have built a .NET Core server that is linked up to a postgres database but what I'm attempting to do now is send requests to the server from a mobile app to execute the CRUD functions with the server. This is so the mobile can send requests that will be an object using a model that's setup in both server and mobile app to be the same. Then the server will POST that request to the database.
This code is on the mobile app that makes a baseAddress for the server and then the other code is inside a save method that turns the object into json string and presumably sends it to the controller.
private static readonly HttpClient sharedClient = new()
{
BaseAddress = new Uri("http://10.188.144.18:5240/AandEBacklog"),
};
using StringContent jsonContent = new(JsonSerializer.Serialize(new { note }),
Encoding.UTF8,
"application/json");
using HttpResponseMessage response = await sharedClient.PostAsync("MobileResponse", jsonContent);
I know that I need to do something with routing in the program.cs file in the server
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
I have a controller that connects to the database but don't know weather I can use the httpRequest in that controller or if I need to send it to another one and then the other controller handles it
using Microsoft.AspNetCore.Mvc;
namespace delamainServer.Controllers;
[ApiController]
[Route("[controller]")]
public class AandEBacklogController : ControllerBase
{
//CONNECTING TO DATABASE.
private readonly DataContext context;
//var httpRequest = HttpContext.Request;
public AandEBacklogController(DataContext context)
{
this.context = context;
}
//post method example to add entry
[HttpPost]
public async Task<ActionResult<List<AandEBacklog>>> Addemrgncy(AandEBacklog booking)
{
context.AandEBacklogs.Add(booking);
await context.SaveChangesAsync();
return Ok(await context.AandEBacklogs.ToListAsync());
}
}
Many thanks in advance
For client part:
var client = new HttpClient() { BaseAddress = new Uri("http://10.188.144.18:5240") };
var content = new StringContent("yourJsonString", Encoding.UTF8, "application/json");
var response = await client.PostAsync("/AandEBacklog", content);
var responseString = await response.Content.ReadAsStringAsync();
EDIT:
Let's setup simple GET endpoint:
[ApiController]
[Route("[controller]")]
public class TimeController : ControllerBase
{
public ActionResult<string> GetCurrentTime() => $"{DateTime.Now}";
}
Verify it works from browser (e.g. http://localhost:5000/Time).
If it works try client from console or Xamarin app:
var client = new HttpClient() { BaseAddress = new Uri("http://localhost:5000") };
var response = await client.GetAsync("/Time");
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
I'm working on an ASP.NET MVC application which has an external reference like this:
public class AuthorizationApi : BaseApi
{
public AuthorizationApi()
{
}
public Configuration LogIn(string username, string password)
{
return LogIn(new Credentials(username, password));
}
public Configuration LogIn(Credentials credentials)
{
AuthLoginWithHttpInfo(credentials);
//missing code
return configuration;
}
protected ApiResponse<object> AuthLoginWithHttpInfo(Credentials credentials)
{
string path = "/auth/login";
RestResponse response = (RestResponse)base.Configuration.ApiClient.CallApiAsync(path, Method.Post, ComposeEmptyQueryParams(), ComposeBody(credentials), ComposeAcceptHeaders(HeaderContentType.None), ComposeEmptyFormParams(), ComposeEmptyFileParams(), ComposeEmptyPathParams(), ComposeContentHeaders(HeaderContentType.Json | HeaderContentType.Xml | HeaderContentType.WwwForm)).Result;
VerifyResponse(response, "AuthLogin");
return GetResponseHeaders(response);
}
}
Calling this code from the web application like so, hangs at LogIn and never returns:
AuthorizationApi api = new AuthorizationApi();
var config = api.LogIn(); //hangs, never returns
The specific line where it hangs is in the external library, where the .RESULT is added to the obvious async method. I have no control over it, and cannot change it:
RestResponse response = (RestResponse)base.Configuration.ApiClient.CallApiAsync(path, Method.Post, ComposeEmptyQueryParams(), ComposeBody(credentials), ComposeAcceptHeaders(HeaderContentType.None), ComposeEmptyFormParams(), ComposeEmptyFileParams(), ComposeEmptyPathParams(), ComposeContentHeaders(HeaderContentType.Json | HeaderContentType.Xml | HeaderContentType.WwwForm)).Result;
Calling from a new Task, sometimes works, sometimes doesn't:
AuthorizationApi api = new AuthorizationApi();
System.Threading.Tasks.Task loginTask = System.Threading.Tasks.Task.Factory.StartNew(() =>
{
configuration = authApi.LogIn();
});
loginTask.Wait(); //hangs here
How to properly call the LogIn() method from an ASP.NET MVC app?
I'm workin on a MVC Aps.Net Core project and I have this situation :
User A is loggedin device A, and user B is trying to login in device A. I allow to login the user B to device A without problem, but in that case I show pop-up message to user A that user A now is disconected from device A.
Evrithing works fine. I call WebApi where I have SQL function, and that function do all the job. The problem is that I have the same code(that call the WebApi) in each function on my project. So I was thinking to make custom middleware so in that way I don't need to replace that code in every function/method in my project.
This is what I tried :
public class Middleware
{
private readonly RequestDelegate _next;
string strBaseUrl = string.Empty;
string strMappaturaUrl = string.Empty;
private readonly IConfiguration config;
private readonly HttpClient client;
public Middleware(RequestDelegate next, IConfiguration _config, HttpClient _client)
{
_next = next;
client = _client;
config = _config;
strBaseUrl = config.GetValue<string>("AppSettings:BaseUrl");
strMappaturaUrl = config.GetValue<string>("AppSettings:MapUrl");
}
public async Task Invoke(HttpContext httpContext)
{
string returnErrore = string.Empty;
CheckUtenteDTO userRequest = new CheckUtenteDTO();
string strUrlApi = string.Empty;
string strContext = string.Empty;
try
{
userRequest.user = HttpContext.Session.GetString("nomeUten");
userRequest.macchina = HttpContext.Session.GetString("macchina");
//Here I call WebApi where I have SQL functio
strUrlApi = config.GetValue<string>("AppSettings:BaseUrl") + "/Users/CheckLoginUser";
string stringData = JsonConvert.SerializeObject(userRequest);
var contentData = new StringContent(stringData, System.Text.Encoding.UTF8, "application/json");
using (var responseMessage = await client.PostAsync(strUrlApi, contentData))
{
if (responseMessage.IsSuccessStatusCode)
{
strContext = await responseMessage.Content.ReadAsStringAsync();
var strReturn = JsonConvert.DeserializeObject<string>(strContext);
if (string.IsNullOrWhiteSpace(strReturn))
returnErrore = string.Empty;
else
throw new UtenteException(strReturn);
}
else
{
strContext = await responseMessage.Content.ReadAsStringAsync();
throw new Exception(strContext);
}
}
}
catch (UserException ex1)
{
returnErrore = ex1.Message.Trim();
HttpContext.Session.SetString("strErrore", ex1.Message);
HttpContext.Session.SetString("nextAction", "LogoutAfterCheck");
HttpContext.Session.SetString("nextController", "Login");
}
catch (Exception ex)
{
returnErrore = ex.Message.Trim();
HttpContext.Session.SetString("strErrore", ex.Message);
HttpContext.Session.SetString("nextAction", "Index");
HttpContext.Session.SetString("nextController", "HomeScreen");
}
return Json(returnErrore);
//return _next(httpContext);
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class MiddlewareExtensions
{
public static IApplicationBuilder UseMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<Middleware>();
}
}
}
And I get this errors .
Is it possible to do it in this way?
Any suggestions how to fix this?
Thanks in advance!
That looks like your middleware don't have access to HttpContext and thus the error. In such case, you can pass the context as a parameter to your middleware from your presentation layer where you have access to HttpContext and calling the Middleware function.
Essentially, you are using only the below two parameters from session .. then why not just extract them in your presentation layer and pass them as argument to the middleware function
userRequest.user = HttpContext.Session.GetString("nomeUten");
userRequest.macchina = HttpContext.Session.GetString("macchina");
Change your Invoke method signature to
Task Invoke(string user, string macchina) //assuming both are type string
Using ASP.NET Core 2.0 for 1st time.
I have a web project which references a DLL that i have created.
In this DLL is a simple method...
namespace InformedWorkerApi
{
[Route("api/[controller]")]
public class RegistrationController: Controller
{
private readonly IAccountRepository _accountRepository;
public RegistrationController(IAccountRepository accountRepository)
{
_accountRepository = accountRepository;
}
[HttpPost()]
[Route("SignOn")]
public async Task<InformedWorkerModels.Account> SignOn([FromBody]SignOnRequest model)
{
return await _accountRepository.SignOn(model.EmailAddress, model.Password);
}
}
}
I have also created a test project which references my DLL...
[TestMethod]
public async Task SignOn()
{
var webHostBuilder = new WebHostBuilder()
.UseStartup<Startup>();
using (var host = new TestServer(webHostBuilder))
{
using (var client = host.CreateClient())
{
var requestData = new SignOnRequest { EmailAddress = "emailAddress", Password= "password" };
var content = new StringContent(JsonConvert.SerializeObject(requestData), Encoding.UTF8, "application/json");
var response = await client.PostAsync("api/Registration/SignOn", content);
//do some asserts here
}
}
}
I get the error status code 404 not found.
What am i getting so wrong here please?
You have email and password as part of the route but send them as content in the body. that wont match the route template for the action and thus 404 Not Found.
Create a model to hold the data
public class SignOnRequest {
[Required]
public string emailAddress { get; set; }
[Required]
public string password { get; set; }
}
Also for core you have to specify with parameter attributes where the framework should look for parameters.
[Route("api/[controller]")]
public class RegistrationController : Controller{
[HttpPost()]
[Route("SignOn")] // Matches POST api/Registration/SignOn
public async Task<IActionResult> SignOn([FromBody]SignOnRequest model) {
if(ModelState.IsValid) {
var response = await _accountRepository.SignOn(model.emailAddress, model.password);
return Ok(response);
}
return BadRequest();
}
}
Which should now match the request being made in the integration test
var requestData = new { emailAddress = "emailAddress", password = "password" };
var content = new StringContent(JsonConvert.SerializeObject(requestData), Encoding.UTF8, "application/json");
var response = await client.PostAsync("api/Registration/SignOn", content);
As you also mentioned that the controller is in another assembly you would need to make sure that the controller is registered with the ServiceCollection within Startup so that the framework is aware of how to resolve the controller. Update the ConfigureServices to include
services.AddMvc()
.AddApplicationPart(typeof(RegistrationController).GetTypeInfo().Assembly)
.AddControllersAsServices();
as referenced from the following answer ASP.NET Core MVC controllers in separate assembly
I just created an ASP .NET MVC 5 Web API project and added the Entity Framework model and other things to get it working with ASP. NET Identity.
Now I need to create a simple authenticated request to the standard method of that API out there from the WPF Client app.
ASP .NET MVC 5 Web API code
[Authorize]
[RoutePrefix("api/Account")]
public class AccountController : ApiController
// GET api/Account/UserInfo
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("UserInfo")]
public UserInfoViewModel GetUserInfo()
{
ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
return new UserInfoViewModel
{
UserName = User.Identity.GetUserName(),
HasRegistered = externalLogin == null,
LoginProvider = externalLogin != null ? externalLogin.LoginProvider : null
};
}
WPF Client code
public partial class MainWindow : Window
{
HttpClient client = new HttpClient();
public MainWindow()
{
InitializeComponent();
client.BaseAddress = new Uri("http://localhost:22678/");
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json")); // It tells the server to send data in JSON format.
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Test();
}
private async void Test( )
{
try
{
var response = await client.GetAsync("api/Account/UserInfo");
response.EnsureSuccessStatusCode(); // Throw on error code.
var data = await response.Content.ReadAsAsync<UserInfoViewModel>();
}
catch (Newtonsoft.Json.JsonException jEx)
{
// This exception indicates a problem deserializing the request body.
MessageBox.Show(jEx.Message);
}
catch (HttpRequestException ex)
{
MessageBox.Show(ex.Message);
}
finally
{
}
}
}
It seems like it is connecting to the host and I am getting the correct error. That is ok.
Response status code does not indicate success: 401 (Unauthorized).
The main problem that I am not sure how to send username and password using WPF Client...
(Guys, I am not asking whether I have to encrypt it and use Auth Filter over API method implementations. I will do this for sure later...)
I heard that I have to send username and password in the header request... but I don't know how it can be done by using HttpClient client = new HttpClient();
Thanks for any clue!
P.S. Have I replace HttpClient with WebClient and use Task (Unable to authenticate to ASP.NET Web Api service with HttpClient)?
You can send over the current logged on user like so:
var handler = new HttpClientHandler();
handler.UseDefaultCredentials = true;
_httpClient = new HttpClient(handler);
then you can create your own authorization filter
public class MyAPIAuthorizationFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
//perform check here, perhaps against AD group, or check a roles based db?
if(success)
{
base.OnActionExecuting(actionContext);
}
else
{
var msg = string.Format("User {0} attempted to use {1} but is not a member of the AD group.", id, actionContext.Request.Method);
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
Content = new StringContent(msg),
ReasonPhrase = msg
});
}
}
}
then use [MyAPIAuthorizationFilter] on each action in your controller that you want to secure.