HttpPost with JSON parameter is not working in ASP.NET Core 3 - json

So, I migrated my RestAPI project to ASP.NET Core 3.0 from ASP.NET Core 2.1 and the HttpPost function that previously worked stopped working.
[AllowAnonymous]
[HttpPost]
public IActionResult Login([FromBody]Application login)
{
_logger.LogInfo("Starting Login Process...");
IActionResult response = Unauthorized();
var user = AuthenticateUser(login);
if (user != null)
{
_logger.LogInfo("User is Authenticated");
var tokenString = GenerateJSONWebToken(user);
_logger.LogInfo("Adding token to cache");
AddToCache(login.AppName, tokenString);
response = Ok(new { token = tokenString });
_logger.LogInfo("Response received successfully");
}
return response;
}
Now, the login object has null values for each property. I read here, that
By default, when you call AddMvc() in Startup.cs, a JSON formatter, JsonInputFormatter, is automatically configured, but you can add additional formatters if you need to, for example to bind XML to an object.
Since AddMvc was removed in aspnetcore 3.0, now I feel this is why I am unable to get my JSON object anymore. My Startup class Configure function looks like this:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseRouting();
//app.UseAuthorization();
//app.UseMvc(options
// /*routes => {
// routes.MapRoute("default", "{controller=Values}/{action}/{id?}");
//}*/);
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapRazorPages();
});
}
The request I am sending through postman (raw and JSON options are selected)
{
"AppName":"XAMS",
"licenseKey": "XAMSLicenseKey"
}
UPDATES
Postman Header: Content-Type:application/json
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//_logger.LogInformation("Starting Log..."); //shows in output window
services.AddSingleton<ILoggerManager, LoggerManager>();
services.AddMemoryCache();
services.AddDbContext<GEContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
//services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
services.AddControllers();
services.AddRazorPages();
//Authentication
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = "https://localhost:44387/";
options.Audience = "JWT:Issuer";
options.TokenValidationParameters.ValidateLifetime = true;
options.TokenValidationParameters.ClockSkew = TimeSpan.FromMinutes(5);
options.RequireHttpsMetadata = false;
});
services.AddAuthorization(options =>
{
options.AddPolicy("GuidelineReader", p => {
p.RequireClaim("[url]", "GuidelineReader");
});
});
//
}
Application.cs
public class Application
{
public string AppName;
public string licenseKey;
}

With you updated code, I think the reason is you didn't create setter for your properties.
To fix the issue, change your Application model as below:
public class Application
{
public string AppName {get;set;}
public string licenseKey {get;set;}
}

Related

Can't seem to return my model using ASP.NET MVC and Entity Framework

This is my code, built on ASP.NET MVC and Entity Framework:
[HttpPost]
[Route("DeskBooking")]
public JsonResult DeskBooking(string dpStart, string dpEnd, int tmStart, int tmEnd)
{
DateTime dpStartCon = DateTime.Parse(GetDateStart(dpStart));
DateTime dpEndCon = DateTime.Parse(GetDateEnd(dpEnd));
using (Models.nhsdmsEntities ctx = new Models.nhsdmsEntities())
{
List<Models.tblDeskBooking> tblDB = ctx.tblDeskBookings
.Where(x => dpStartCon <= x.DateStart &&
x.DateEnd <= dpEndCon &&
tmStart >= x.TimeStart &&
tmEnd <= x.TimeEnd).ToList();
return Json(new { data = tblDB }, JsonRequestBehavior.AllowGet);
}
}
The tblDB has 3 rows but still on the client side I get this error:
An unhandled exception was generated during the execution of the current web request
[ObjectDisposedException: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.]
Client-side code:
$(document).on("click", "#btnBookDeskEmp", function () {
var dpStart = $("#dpStart").val();
var dpEnd = $("#dpEnd").val();
var tmStart = $("#tmStart").val();
var tmEnd = $("#tmEnd").val();
AjaxReq(function (data) {
}, "DeskBooking", { dpStart: dpStart, dpEnd: dpEnd, tmStart: parseInt(tmStart), tmEnd: parseInt(tmEnd) });
})
function AjaxReq(callback, action, data) {
$.ajax({
url: "/Home/" + action,
method: "POST",
data: data,
})
.done(function (data) {
callback(data);
})
.fail(function (e) {
alert("error");
})
.always(function () {
console.log("complete");
});
}
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace NHSDMS.Models
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
public partial class nhsdmsEntities : DbContext
{
public nhsdmsEntities()
: base("name=nhsdmsEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<tblDesk> tblDesks { get; set; }
public virtual DbSet<tblRoom> tblRooms { get; set; }
public virtual DbSet<tblDeskBooking> tblDeskBookings { get; set; }
}
}
In the edmx file, i had to delete everything from the navigation properties as this was messing up my namesspace. if you would like more info i can show sceenshots.

post_logout_redirect_uri ASP NET Core 2.2 AzureAD Razor Class Library RCL

We have tried using the sample
https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/
Walked through the sample and all works.
We can't get it to redirect after logout process. Also, it seems the account controller is not there but it is called in _layout.chtml this must be something new.
Yes, it does redirect to the application - what I'd like it to do is redirect to a different page.
You can redirect user to another page after sign-out by setting the OnSignedOutCallbackRedirect event :
In Startup.cs add using System.Threading.Tasks;
Config your new redirect url in OnSignedOutCallbackRedirect event :
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.Authority = options.Authority + "/v2.0/";
options.TokenValidationParameters.ValidateIssuer = false;
options.Events.OnSignedOutCallbackRedirect = (context) =>
{
context.Response.Redirect("/Home/About");
context.HandleResponse();
return Task.CompletedTask;
};
});
The account controller code is built into the framework now. You can see it in Microsoft.AspNetCore.Authentication.AzureAD.UI.AzureAD.Controllers.Internal (see https://github.com/aspnet/AADIntegration/blob/0efa96de73e3235fbfc55cfe51d9547a693010cc/src/Microsoft.AspNetCore.Authentication.AzureAD.UI/Areas/AzureAD/Controllers/AccountController.cs):
namespace Microsoft.AspNetCore.Authentication.AzureAD.UI.AzureAD.Controllers.Internal
{
[AllowAnonymous]
[Area("AzureAD")]
[NonController]
[Route("[area]/[controller]/[action]")]
internal class AccountController : Controller
{
public IOptionsMonitor<AzureADOptions> Options
{
get;
}
public AccountController(IOptionsMonitor<AzureADOptions> options)
{
this.Options = options;
}
[HttpGet("{scheme?}")]
public IActionResult SignIn([FromRoute] string scheme)
{
scheme = scheme ?? AzureADDefaults.AuthenticationScheme;
string str = base.Url.Content("~/");
return this.Challenge(new AuthenticationProperties()
{
RedirectUri = str
}, new String[] { scheme });
}
[HttpGet("{scheme?}")]
public IActionResult SignOut([FromRoute] string scheme)
{
scheme = scheme ?? AzureADDefaults.AuthenticationScheme;
AzureADOptions azureADOption = this.Options.Get(scheme);
string str = base.Url.Page("/Account/SignedOut", null, null, base.Request.Scheme);
return this.SignOut(new AuthenticationProperties()
{
RedirectUri = str
}, new String[] { azureADOption.CookieSchemeName, azureADOption.OpenIdConnectSchemeName });
}
}
}
Unfortunately, I have not be able to force a redirect after logout. Instead, I see a page that says "You have successfully signed out." I'd like to know how to redirect the user back to the Index page.
I had to override the signedOut page manually by adding this to a controller:
[AllowAnonymous]
[HttpGet]
[Route("/MicrosoftIdentity/Account/SignedOut")]
public IActionResult SignedOut()
{
return Redirect(<MyRealSignedOutRedirectUri>);
}

Can not pull updated data from mysql database

My ASP.NET MVC & EF project has a base controller as follows:
public class BaseController : Controller
{
private Context _database;
public Context Db
{
get
{
if (_database == null)
{
_database = new Context();
}
return _database;
}
}
protected override void Dispose(bool disposing)
{
if (_database != null)
{
_database.Dispose();
}
base.Dispose(disposing);
}
My ajax save setting code is:
public JsonResult SiteGenelAyarlari(List<GeneralSettings> gs)
{
if (ModelState.IsValid)
{
gs.ForEach(item => Db.GeneralSettings.AddOrUpdate(s => s.LanguageId, item));
Db.SaveChanges();
}
return Json("Saved fine.", JsonRequestBehavior.AllowGet);
}
But when I update a value in the database, after a page refresh the new values do not get pulled. What am I missing?
If I re-run project, new values are being returned fine.

Azure MobileSeviceClient InvokeApiAsync - Newtonsoft.Json.JsonReaderException

I'm trying to call a method on a custom api controller on my azure mobile services client.
If I hit the path in the browser it returns data just fine. When trying to call it from my app I get the following error
"Newtonsoft.Json.JsonReaderException: Error reading string. Unexpected token: StartObject. Path '', line 1, position 1."
public async Task<string> AuthUser (string email, string pass)
{
var id = await client.InvokeApiAsync<string>(
"Login/AuthUser",
System.Net.Http.HttpMethod.Get,
new Dictionary<string, string>() {
{"emailAddress", email },
{"password",pass }
}
);
if (id != null)
{
return id.ToString();
}
else
{
return "";
}
}
Here's the controller I'm calling
using System.Linq;
using System.Web.Http;
using System.Web.Http.Description;
using MyAppService.DataObjects;
using MyAppService.Models;
using Microsoft.Azure.Mobile.Server.Config;
namespace MyAppService.Controllers
{
[MobileAppController]
public class LoginController : ApiController
{
private MyAppContext db = new MyAppContext ();
[HttpGet]
[ActionName("AuthUser")]
public IHttpActionResult Login(string emailAddress, string password)
{
var login = db.Members.FirstOrDefault(m => m.Email == emailAddress && m.Password == password);
if (login != null)
{
return Ok(new {Id = login.Id });
}
else
{
return Unauthorized();
}
}
}
}
EDIT: The issue was the return type from the controller. Changed it to string and it worked.
The issue was the return type from the controller. Changed it to string and it worked

How to send JSON data from ASP.NET MVC 5 back to client side Angular (i.e. during authentication)

i have to redirect to a different view if authenticated and I need to send JSON data containing the userid and username to be used by AngularJS.
The Redirect works but I am not sure how to send the authenticated user information as JSON data to the client-side.
Can some one help me?
Here are some code that I have in MVC side...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using TVS.Core.Interfaces;
using TVS.Domain;
using TVS.UI.Models;
namespace TVS.UI.Controllers
{
public class homeController : Controller
{
private readonly IUser _IUser;
public homeController(IUser IUser)
{
_IUser = IUser;
}
public ActionResult RedirectAngular()
{
return View();
}
[HttpGet]
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(UserModel model)
{
if (ModelState.IsValid)
{
if (_IUser.IsValidUser(model.Login,model.Password))
{
FormsAuthentication.SetAuthCookie(model.Login, false);
return RedirectToAction("RedirectAngular", "home");
}
else
{
// ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
//}
}
return View();
}
public ActionResult LogOff()
{
FormsAuthentication.SignOut();
return RedirectToAction("Login", "home");
}
}
}
You could just put it in a model or ViewBag and render the view if the logon form is actually a page and whatever page you redirect to when authenticated is another. Then just use the model / ViewBag to populate a page / app Setting javascript global or push them into angular value or constant like so:
//Controller Action
public ActionResult Logon(string username, string password) {
//authentication successful...
//using ViewBag, but model will do as well..
ViewBag.UserId = 12; //for example...
ViewBag.UserName = "John Doe";
return View();
}
#* View
somewhere near end of <body> tag...
*#
<script src=".../angular.js">
<script>
//or load this from a file...
angular.module('moduleName', []);
</script>
<script>
//this need to be in page!!
angular.moduel('moduleName')
.value('appSettings', {
userId : #ViewBag.UserId,
userName: '#ViewBag.UserName'
});
</script>
<script>
//this can be loaded from file...
angular.controller('controllerName', ctrlFn);
ctrlFn.$inject = ['$log', 'appSettings'];
function ctrlFn($log, appSettings) {
//do something with appSetting here...
$log.info(appSettings.userId, appSettings.userName);
}
</script>
If this is not what you meant, and you are pushing the form info as Ajax and your Angular is actually a SPA then you need to use AJAX to marshal data between server and client side...
Just return a JsonResult like so...
[HttpPost]
public ActionResult Logon(string username, string password)
{
//authenticate here... assume succesful...
var user = new { userId = 12, userName = "John Doe" }
return Json(user, "application/json", Encoding.UTF8);
}
in your angular, just handle whatever getting returned back like so:
<script>
angular.module('moduleName')
.factory('loginSvc', svcFn);
svcFn.$inject = ['$http'];
function svcFn($http) {
var svc = {
login: login
};
return svc;
function login(username, password) {
return $http.post(
'/api/login',
angular.toJson({username: username, password: password});
}
}
angular.module('moduleName')
.controller('controllerName', ctrlFn);
ctrlFn.$inject = ['$log', 'loginSvc'];
function ctrlFn($log, loginSvc) {
var self = this;
self.username = "";
self.password = "";
self.login = login;
function login() {
loginSvc.login(username, password)
.then(handleLoginSuccess)
.catch(handleLoginFailure);
}
function handleLoginSuccess(userInfo) {
$log.info(userInfo); //this should contain logged in user id and username
}
//some other functions here...
}
</script>