frombody object is null in .net core 3 - .net-core-3.0

[HttpPost("add-car")]
public async Task<IActionResult> AddCarAsync([FromBody] AddCarInputDtos addCarInputDtos)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
}
public class AddCarInputDtos
{
public int? CodeParent { get; set; }
Required(ErrorMessage = "CodeCarList parameter is mandatory.")]
public int? CodeCarList { get; set; }}
[EnumDataType(typeof(YesNoEnum), ErrorMessage = "YesNoEnum value doesn't exist within enum")]
public YesNoEnum? FeatureLoad { get; set; }
}
When I call this API method with postman in application/json format and trace the code object is null and it returns:
{
"$.featureLoad": [
"The JSON value could not be converted to System.Nullable`1[Jinavat.Backend.Api.Dtos.General.YesNoEnum]. Path: $.featureLoad | LineNumber: 0 | BytePositionInLine: 268."
]
}
Please help me to resolve this problem.

Try adding NewtonsoftJson explicitly in ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
// services.AddABunchOfStuff();
services.AddNewtonsoftJson();
// services.AddMoreStuff();
}
as per these docs: https://learn.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.0&tabs=visual-studio#jsonnet-support

Related

How to get API response key values in PascalCase as same as the object variable name in .net core 3.1 only for one controller or one function?

This is my Object Class
public class MyObject
{
Public string Var1 { get; set; }
Public string Var2 { get; set; }
}
This is a get function of my controller class
[HttpGet]
public IActionResult GetObjList()
{
return Ok(new GenericModel<List<MyObject>>
{
Data = myobjectList
});
}
The GenericModel contains
public class GenericModel<T>
{
public T Data { get; set; }
public string[] Errors { get; set; }
}
My expected result look like this
{
"Data": [
{
"Var1": "val1",
"Var2": "val2"
}
]
}
But I'm getting this,
{
"data": [
{
"var1": "val1",
"var2": "val2"
}
]
}
I just want to get the output key values as same as the object variables, (in PascalCase)
I tried the solutions to add "AddJsonOptions" into the Startup.cs but they did not work. And I want the response as Pascal case, only for this controller requests, not in all requests including other controllers. (Sounds odd, but I want to try it) Are there any solutions? Is is impossible?
There may be another solution but I suggest building ContentResult yourself with JsonSerializer:
[HttpGet]
public IActionResult GetObjList()
{
return this.Content(JsonSerializer.Serialize(yourResult, yourJsonOption), "application/json");
}
For Pascal Case serialization use this code in Startup.cs:
services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy= null;
);

Unable to validate Person<T> object using FluentValidation

I have code like this
public class Person<T>
{
public Person()
{
Result = default(T);
}
public bool IsValid { get; set; }
public T Result { get; set; }
public int StatusCode { get; set; }
}
public class PersonValidator<T> : AbstractValidator<Person<T>>
{
public PersonValidator()
{
RuleFor(r => r.StatusCode).GreaterThan(0);
}
}
in Startup.cs
mvcBuilder.AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining(typeof(PersonValidator<>)));
There is no error and error count is coming zero even though rule is not satisfied.
When I remove this T from PersonValidator and update AbstractValidator<Person<T>> to AbstractValidator<Person<long>> then it works fine.
I have added validators as PersonValidator. Also registered validator as above. I have to validate generic class, please help understand what is going wrong here, and how I can fix it.

Automapper - Mapper already initialized error

I am using AutoMapper 6.2.0 in my ASP.NET MVC 5 application.
When I call my view through controller it shows all things right. But, when I refresh that view, Visual Studio shows an error:
System.InvalidOperationException: 'Mapper already initialized. You must call Initialize once per application domain/process.'
I am using AutoMapper only in one controller. Not made any configuration in any place yet nor used AutoMapper in any other service or controller.
My controller:
public class StudentsController : Controller
{
private DataContext db = new DataContext();
// GET: Students
public ActionResult Index([Form] QueryOptions queryOptions)
{
var students = db.Students.Include(s => s.Father);
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.CreateMap<Student, StudentViewModel>();
});
return View(new ResulList<StudentViewModel> {
QueryOptions = queryOptions,
Model = AutoMapper.Mapper.Map<List<Student>,List<StudentViewModel>>(students.ToList())
});
}
// Other Methods are deleted for ease...
Error within controller:
My Model class:
public class Student
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string CNIC { get; set; }
public string FormNo { get; set; }
public string PreviousEducaton { get; set; }
public string DOB { get; set; }
public int AdmissionYear { get; set; }
public virtual Father Father { get; set; }
public virtual Sarparast Sarparast { get; set; }
public virtual Zamin Zamin { get; set; }
public virtual ICollection<MulaqatiMehram> MulaqatiMehram { get; set; }
public virtual ICollection<Result> Results { get; set; }
}
My ViewModel Class:
public class StudentViewModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string CNIC { get; set; }
public string FormNo { get; set; }
public string PreviousEducaton { get; set; }
public string DOB { get; set; }
public int AdmissionYear { get; set; }
public virtual FatherViewModel Father { get; set; }
public virtual SarparastViewModel Sarparast { get; set; }
public virtual ZaminViewModel Zamin { get; set; }
}
If you want/need to stick with the static implementation in a unit testing scenario, note that you can call AutoMapper.Mapper.Reset() before calling initialize. Do note that this should not be used in production code as noted in the documentation.
Source: AutoMapper documentation.
When you refresh the view you are creating a new instance of the StudentsController -- and therefore reinitializing your Mapper -- resulting in the error message "Mapper already initialized".
From the Getting Started Guide
Where do I configure AutoMapper?
If you're using the static Mapper method, configuration should only happen once per AppDomain. That means the best place to put the configuration code is in application startup, such as the Global.asax file for ASP.NET applications.
One way to set this up is to place all of your mapping configurations into a static method.
App_Start/AutoMapperConfig.cs:
public class AutoMapperConfig
{
public static void Initialize()
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Student, StudentViewModel>();
...
});
}
}
Then call this method in the Global.asax.cs
protected void Application_Start()
{
App_Start.AutoMapperConfig.Initialize();
}
Now you can (re)use it in your controller actions.
public class StudentsController : Controller
{
public ActionResult Index(int id)
{
var query = db.Students.Where(...);
var students = AutoMapper.Mapper.Map<List<StudentViewModel>>(query.ToList());
return View(students);
}
}
I've used this method before and it worked till version 6.1.1
Mapper.Initialize(cfg => cfg.CreateMap<ContactModel, ContactModel>()
.ConstructUsing(x => new ContactModel(LoggingDelegate))
.ForMember(x => x.EntityReference, opt => opt.Ignore())
);
Since version 6.2, this doesn't work any more. To correctly use Automapper create a new Mapper and us this one like this:
var mapper = new MapperConfiguration(cfg => cfg.CreateMap<ContactModel, ContactModel>()
.ConstructUsing(x => new ContactModel(LoggingDelegate))
.ForMember(x => x.EntityReference, opt => opt.Ignore())).CreateMapper();
var model = mapper.Map<ContactModel>(this);
In case you really need to "re-initialize" AutoMapper you should switch to the instance based API to avoid System.InvalidOperationException: Mapper already initialized. You must call Initialize once per application domain/process.
For example, when you are creating the TestServer for xUnit tests you can just set ServiceCollectionExtensions.UseStaticRegistration inside fixure class constructor to false to make the trick:
public TestServerFixture()
{
ServiceCollectionExtensions.UseStaticRegistration = false; // <-- HERE
var hostBuilder = new WebHostBuilder()
.UseEnvironment("Testing")
.UseStartup<Startup>();
Server = new TestServer(hostBuilder);
Client = Server.CreateClient();
}
For Unit Testing, you can add Mapper.Reset() to your unit test class
[TearDown]
public void TearDown()
{
Mapper.Reset();
}
You can use automapper as Static API and Instance API ,
Mapper already initialized is common issue in Static API , you can use mapper.Reset()
where you initialized mapper but this this not an answer at all.
Just try with instance API
var students = db.Students.Include(s => s.Father);
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<Student, StudentViewModel>();
});
IMapper iMapper = config.CreateMapper();
return iMapper.Map<List<Student>, List<StudentViewModel>>(students);
Automapper 8.0.0 version
AutoMapper.Mapper.Reset();
Mapper.Initialize(
cfg => {
cfg.CreateMap<sourceModel,targetModel>();
}
);
You can simply use Mapper.Reset().
Example:
public static TDestination MapToObject<TSource, TDestination>(TSource Obj)
{
Mapper.Initialize(cfg => cfg.CreateMap<TSource, TDestination>());
TDestination tDestination = Mapper.Map<TDestination>(Obj);
Mapper.Reset();
return tDestination;
}
If you are using MsTest you can use the AssemblyInitialize attribute so that mapping gets configured only once for that assembly (here test assembly). This is generally added into to the base class of controller unit tests.
[TestClass]
public class BaseUnitTest
{
[AssemblyInitialize]
public static void AssemblyInit(TestContext context)
{
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.CreateMap<Source, Destination>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.EmailAddress));
});
}
}
I hope this answer helps
If you are using Mapper in UnitTest and your tests more then one, You may use Mapper.Reset()
`
//Your mapping.
public static void Initialize()
{
Mapper.Reset();
Mapper.Initialize(cfg =>
{
cfg.CreateMap<***>
}
//Your test classes.
[TestInitialize()]
public void Initialize()
{
AutoMapping.Initialize();
}`
private static bool _mapperIsInitialized = false;
public InventoryController()
{
if (!_mapperIsInitialized)
{
_mapperIsInitialized = true;
Mapper.Initialize(
cfg =>
{
cfg.CreateMap<Inventory, Inventory>()
.ForMember(x => x.Orders, opt => opt.Ignore());
}
);
}
}

Unit tests fails after upgrading to .net core 2

Can someone maybe explain to me what this means and why am i getting it.
System.InvalidOperationException : When called from 'VisitLambda',
rewriting a node of type 'System.Linq.Expressions.ParameterExpression'
must return a non-null value of the same type. Alternatively, override
'VisitLambda' and change it to not visit children of this type.
I am getting it from my unit tests I am running the latest .net core 2 with EF core. all my tests were fine till i upgraded then i started getting the error.
The funny thing is, is that when i run the project the line were it fails in the the tests is ok.
This is my Test
[Fact]
public async Task GetUserProfileAsync_Where_Employee_Exist_Test()
{
// Given
var user = TestPrincipal.CreatePrincipalForEmployeeUser();
using (var factory = new TestContextFactory())
using (var context = factory.CreateInMemoryDatabase<ApplicationContext>())
{
this.SetDependencies(context);
var data = EmployeeValueHelper.GetEmployeeValues();
context.AddRange(data);
context.SaveChanges();
var sut = new ProfileService(new DbContextRepository<Data.Models.Employees.Employee>(context), this.userService, this.moqEmploymentStatusService.Object);
// When
// -> this method goes to a service and calls the below FindByIdAsync
var actual = await sut.GetProfileForUserAsync(user);
// Then
Assert.Equal(10, actual.EmployeeId);
}
}
public async Task<Employee> FindByIdAsync(long id)
{
var profile = await this.repository.Set
.Include(_ => _.Address) --> IT FAILS ON THIS LINE, IF I REMOVE THE INCLUDE THEN IT WORKS
.Include(_ => _.EmployeeImage)
.SingleOrDefaultAsync(_ => _.EmployeeId == id);
if (profile == null)
{
return null;
}
return profile;
}
UPDATE
Service Layer
public class ProfileService : GenericService<Employee>, IProfileService
{
private readonly DbContextRepository<Employee> repository;
private readonly IUserService userService;
public ProfileService(DbContextRepository<Employee> repository, IUserService userService)
: base(repository)
{
this.repository = repository;
this.userService = userService;
}
public Task<Employee> GetProfileForUserAsync(ClaimsPrincipal user)
{
var id = this.userService.GetEmployeeId(user);
return id.HasValue ? this.FindByIdAsync(id.Value) : null;
}
public async Task<Employee> FindByIdAsync(long id)
{
var profile = await this.repository.Set
.Include(_ => _.Address)
.Include(_ => _.EmployeeImage)
.SingleOrDefaultAsync(_ => _.EmployeeId == id);
if (profile == null)
{
return null;
}
return profile;
}
}
Employee Model
public class Employee : IValidatableObject
{
[Key]
[Column("pkEmpID")]
public long EmployeeId { get; set; }
[Column("fkCompanyID")]
public long CompanyId { get; set; }
public virtual Company Company { get; set; }
[Display(Name = "lblEmpNumber")]
public string EmpNumber { get; set; }
public virtual IList<Address> Address { get; set; } = new List<Address>();
// WITH SOME EXTRA STUFF NOT NEEDED FOR THIS
}
Repository
public class DbContextRepository<TEntity> : IGenericRepository<TEntity>, IDisposable
where TEntity : class
{
public DbContextRepository(ApplicationContext context)
{
this.Context = context;
this.Set = context.Set<TEntity>();
this.SetWithNoTracking = this.Set.AsNoTracking();
}
public ApplicationContext Context { get; }
public DbSet<TEntity> Set { get; }
public IQueryable<TEntity> SetWithNoTracking { get; }
// WITH SOME EXTRA STUFF NOT NEEDED FOR THIS
}
Hope this will shed more light

Custom impromptuobject for json.net deserialization

I was playing around with impromptu interface over a jobject and ran into the following issue
https://code.google.com/p/impromptu-interface/issues/detail?id=17
The issue is marked as 'Won't fix' and in the comments the author says that it could be fixed by implementing a custom impromptuobject.
Anyone have a sample of such an implementation? Or know another solution to this problem?
So the problem is that JArray has GetEnumerator() defined as interface-only, which makes the method no longer duck callable by the DLR. So below I've overriden the trygetmember to check if the result is a JArray's and convert it to a JEnumerable that implements GetEnumerator() in a dlr invokable way.
public class NonRecursiveJArrayConversionDictionary : ImpromptuDictionary{
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if(base.TryGetMember(binder, out result)){
if(result is JArray){
result = ((JArray)result).AsJEnumerable();
}
return true;
}
result = null;
return false;
}
}
However, this will only work for json structures that don't have arrays more then one property deep. You'll either have modify the above to recursively check anytime anything is returned maybe with a proxy, or modify the dictionary indexer's set to check and convert when deserialized instead.
Update: Json.net verion >= 5.0.4.16101 and ImpromptuInterface >= 6.1.4 will work out of the box.
void Main()
{
ICustomer customer = Impromptu.ActLike(JObject.Parse(#"
{
Id: 1,
Name:'Test',
Location:'Somewhere',
Employees: [
{ Id:1, EmployerId:39421, Name:'Joe' },
{ Id:2, EmployerId:39421, Name:'Jane' },
]
}
"));
foreach(var employee in customer.Employees){
employee.Id.Dump();
employee.Name.Dump();
}
}
public interface ICustomer
{
int Id { get; set; }
string Name { get; set; }
string Location { get; set; }
IList<IEmployee> Employees { get; }
}
public interface IEmployee
{
int Id { get; set; }
int EmployerId { get; set; }
string Name { get; set; }
}

Resources