My ASP.NET MVC Forms Send Null

MrBarszcz 20 Reputation points
2025-04-28T03:43:20.6133333+00:00

My ASP.NET Core (or MVC .NET Framework) form is showing unexpected behavior: the data I enter in the fields does not reach my controller correctly, resulting in null properties in my model. I have already checked the 'Network' tab of the browser, and in the POST request I can clearly see the values ​​filled in the 'Payload'/'Request Body'.

Some things I have already tried/checked:

The names of the inputs in the HTML (asp-for/name) exactly match the names of the properties in my model.

The action in my controller is decorated with [HttpPost].

Even with these checks, the values ​​continue to arrive null on the server. Is there any other possible cause for this problem that I can investigate? ResisterCategory.cshtml:

@model CategoryModel

@{
    Layout = "_Layout";
}

<div class="text-center">
    <h1 class="display-4">Cadastrar Categoria</h1>

    <form class="form-control" asp-controller="ControlPanel" asp-action="RegisterCategory" method="post">
        <div class="mb-3">
            <label for="category" class="form-label">Categoria</label>
            <input type="text" asp-for="Category" class="form-control" id="category"  placeholder="Ex: Camisa">
        </div>
        
        <div class="btn-group" role="group">
            <a role="button" class="btn btn-outline-danger" asp-controller="ControlPanel" asp-action="Category">Voltar</a>
            <button type="submit" class="btn btn-primary text-end">Adicionar</button>
        </div>
    </form>
</div>

ControlPanelController.cs:

public class ControlPanelController : Controller {
    private readonly ICategoryRepository _categoryRepository;
    private readonly ISizeRepository _sizeRepository;
    private readonly IColorRepository _colorRepository;

    private readonly ILogger<ControlPanelController> _logger;

    public ControlPanelController(
        ICategoryRepository categoryRepository, ISizeRepository sizeRepository, IColorRepository colorRepository,
        ILogger<ControlPanelController> logger
    ) {
        _categoryRepository = categoryRepository;
        _sizeRepository = sizeRepository;
        _colorRepository = colorRepository;

        _logger = logger;
    }

	// GET
	public IActionResult Category() {
	    // lists the categories and has a button that sends to RegisterCategory, UpdateCategory, DeleteCategory
	    List<CategoryModel> categories = _categoryRepository.FindAll();
	    return View(categories);
	}

	
	public IActionResult RegisterCategory() { // form to register a new category
	    return View();
	}

	// POST
	[HttpPost]
	public IActionResult EditCategory(CategoryModel category) {
	    _categoryRepository.Update(category);
	    return RedirectToAction("Category");
	}

	[HttpPost]
	public IActionResult RegisterCategory(CategoryModel category) {
	    _categoryRepository.Create(category);
	    return RedirectToAction("Category");
	}

CategoryRepository.cs:

public class CategoryRepository : ICategoryRepository {
    private readonly BankContext _context;
    
    public CategoryRepository(BankContext context) {
        _context = context;
    }
    

    // FIND
    public List<CategoryModel> FindAll() {
        return _context.Categories.ToList();
    }

    public CategoryModel FindById(int id) {
        return _context.Categories.FirstOrDefault(x => x.CategoryId == id);
    }

    // UPDATE
    public CategoryModel Update(CategoryModel category) {
        CategoryModel categoryDb = FindById(category.CategoryId);

        if (categoryDb == null) throw new Exception("Houve um erro ao atualizar a categoria");
        
        categoryDb.Category = category.Category;
        
        _context.Categories.Update(categoryDb);
        _context.SaveChanges();
        
        return categoryDb;
    }
    
    // CREATE
    public CategoryModel Create(CategoryModel category) {
        _context.Categories.Add(category);
        _context.SaveChanges();

        return category;
    }
    
    // KILL
    
}

CategoryModel.cs:

public class CategoryModel {
    public int CategoryId { get; set; }
    public string Category { get; set; } = null!;
    public virtual ICollection<ProductCategoryModel> ProductCategories { get; set; } = new List<ProductCategoryModel>();
}

BankContext.cs:

public class BankContext : DbContext {
    public BankContext(DbContextOptions<BankContext> options) : base(options) {
    }


	public DbSet<CategoryModel> Categories { get; set; } = null!;


	protected override void OnModelCreating(ModelBuilder modelBuilder) {
	    // Category
	    modelBuilder.Entity<CategoryModel>()
	        .HasKey(c => c.CategoryId);
	
	    modelBuilder.Entity<CategoryModel>().Property(c => c.CategoryId).HasColumnName("category_id")
	        .ValueGeneratedOnAdd();
	    modelBuilder.Entity<CategoryModel>().Property(c => c.Category).HasColumnName("category").IsRequired()
	        .HasMaxLength(100);
	    modelBuilder.Entity<CategoryModel>().HasMany(c => c.ProductCategories).WithOne(pc => pc.Category)
	        .HasForeignKey(pc => pc.CategoryId).HasConstraintName("FK_ProductCategory_Category");

}

I didn't send it, but it's not just category that sends null, size and color too, the logic is the same

I've used both asp-for and name in the form, both gave an error

I'm using dotnet9 but 8 also gave the same result

ASP.NET Core Training
ASP.NET Core Training
ASP.NET Core: A set of technologies in the .NET Framework for building web applications and XML web services.Training: Instruction to develop new skills.
66 questions
{count} votes

Accepted answer
  1. Michael Taylor 59,026 Reputation points
    2025-04-28T18:54:45.12+00:00

    The issue is with your parameter name for the controller action. If you have the default analyzers enabled for your project then it is actually warning about this behavior. Your controller's parameter name is category.

    Your model has a property called Category as well. Case doesn't matter for model binding. If you look at the data being passed back from a FORM post it is just a series of key-value pairs. The default binder enumerates the key-value pairs and attempts to match each key up to either a parameter name or a property on the model parameter, if any. In your case it sees category and it doesn't know whether you mean the parameter to the action or the property inside the model so it is, in this case, choosing the parameter name. So it ends up creating a new instance of the model and wipes out any data you might have had.

    The fix is easy, use a different name for the parameter to the action, such as item. Your problem will go away.

    1 person found this answer helpful.
    0 comments No comments

2 additional answers

Sort by: Most helpful
  1. Pradeep M 8,585 Reputation points Microsoft External Staff Moderator
    2025-04-28T03:47:18.0566667+00:00

    Hi MrBarszcz,  

    Thank you for reaching out to Microsoft Q & A forum. 

    It appears you’ve covered some key points already. However, here are a few additional things to consider: 

    1.Form Method: Ensure the form uses method="post". 

    2.Model Binding: Verify that the names of your input fields (using asp-for or name) exactly match the model property names, including case sensitivity. 

    3.Nested Properties: If your model contains nested objects, ensure the input names reflect the full path (e.g., Parent.Child.Property). 

    4.ViewModel Consistency: If you are using a ViewModel, ensure it aligns exactly with the model in the controller. 

    5.Antiforgery Token: Confirm that @Html.AntiForgeryToken() is included in your form, and that the controller uses [ValidateAntiForgeryToken] if necessary. 

    6.JavaScript: If JavaScript is modifying the form, verify that all values are correctly set before submission. 

    If the issue continues, please share the relevant code from your view and controller, so we can provide a more accurate and detailed solution. 

    If you have found the answer provided to be helpful, please click on the "Accept answer/Upvote" button so that it is useful for other members in the Microsoft Q&A community. 


  2. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.