Best Practice - CRUD operations MVC4 - crud

I want to know if there is better way to implement CRUD mentioned below.
[HttpGet]
public ActionResult EditStudent(int studentID)
{
Student obj = StudentBAL.GetStudent(id);
return View(obj);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditStudent([Bind(Include="LastName,FirstMidName,EnrollmentDate")]Student model)
{
return View();
}
I don't want to pass StudentID(primary key) to client end as it can be modified easily from developer tools(Firebug etc.). I have excluded studentid on POST request too. Let me know how i can perform update/change without passing primarykey.

Related

How can I add links to other controller methods in generated OpenAPI specs using attributes in ASP.NET Core?

I am using SwaggerGen to generate an OpenAPI spec for our API, and would like to add links between certain endpoints.
OpenAPI 3.0 Links
Is there a way to add an attribute to the controller method that links to another controller method?
For example, if I currently have something like
[HttpPost]
[Route("~/users")]
[ProducesResponseType(typeof(ResponseObject<UserId>), StatusCodes.Status200OK)]
public async Task<IActionResult> CreateUser(...)
{
// Create user
}
[HttpGet]
[Route("~/users/{userId}")]
[ProducesResponseType(typeof(ResponseObject<User>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetUser(...)
{
// Get newly created user
}
Could I somehow link them like
[HttpPost]
[Route("~/users")]
[ProducesResponseType(typeof(ResponseObject<UserId>), StatusCodes.Status200OK)]
[Link(nameof(GetUser), "UserId")]
public async Task<IActionResult> CreateUser(...)
{
// Create user
}
[HttpGet]
[Route("~/users/{userId}")]
[ProducesResponseType(typeof(ResponseObject<User>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetUser(...)
{
// Get newly created user
}
to generate the "links" field as shown in the OpenAPI 3.0 spec linked above?

In Asp Net Core, Do I have to put the Attribute of [Authorize] for both Get and Post Method?

In the controller, normally we have a Get and a Post methods
for example:
[HttpGet]
[Authorize(Policy = "AdminMs")]
public async Task<IActionResult> MSCreate()
{
}
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Policy = "AdminMs")]
public async Task<IActionResult> MSCreate(empolyee)
{
}
Do I have to set the Authorize Attribute for both methods or only for HttpGet?
If you need only authorized access to any of the end points, you have to use [Authorize] on whichever method that corresponds to that endpoint. Having it on one method does not mean that it will restrict the other method even if they have similar method names.

ASP.NET Core Web API - AmbiguousMatchException: The request matched multiple endpoints

I've been looking at this, but still cannot find a solution, here goes:
To return all players, I will pass in something similar to:
http://localhost:7777/api/teams/34fe3b6f-ba23-4657-820a-6c59dd49173a/players
To return a specific player on a specific team, I will pass in somethign similar to:
http://localhost:7777/api/teams/34fe3b6f-ba23-4657-820a-6c59dd49173a/players/f7de7974-9cbb-4c2c-884e-29036d6c2d76
I keep getting the following error:
System.ArgumentException: 'The route parameter name 'id' appears more than one time in the route template. '
Could someone please advise how to fix this?
[Route("api/Teams/{Id}/Players}")]
[ApiController]
public class PlayersController : ControllerBase
{
[HttpGet]
public IActionResult GetAllTeamPlayers(Guid id)
{
return Ok();
}
[HttpGet]
public IActionResult GetTeamPlayer(Guid id, Guid id2)
{
return Ok();
}
}
You should define the route parameters like this:
[Route("api/Teams/{teamId}/}")]
[ApiController]
public class PlayersController : ControllerBase
{
[HttpGet("players")]
public IActionResult GetAllTeamPlayers([FromRoute] Guid teamId)
{
return Ok();
}
[HttpGet("players/{playerId}")]
public IActionResult GetTeamPlayer([FromRoute] Guid teamId, [FromRoute] Guid playerId)
{
return Ok();
}
}

Odata Post Collection FromBody

I'm working on rebuilding an API by converting to aspnetcore from aspnet. An unfortunate roadblck for me has been around Odata in general, one of the concessions I was forced to make was moving a few routes to OData, as a mixture of OData and standard API wasnt compatible with swagger.
Anyhow, One such method (The last one remaining) has the following Signature
[HttpPost]
public IActionResult PostChanges([FromBody] ICollection<BulkEditDTO> changeSet)
{
if (!ModelState.IsValid)
{
var error = ModelState.Values.Select(x => x.Errors).FirstOrDefault();
return BadRequest(ModelState);
}
//TODO:Get data?
}
Object
public class BulkEditDTO
{
[Key]
[DataMember]
public int Id { get; set; }
[DataMember]
public SomeDTO Changes { get; set; }
}
Now I feel like I've tried every combination of Functions, complex types, actions, ODataActionParamaers that i can think of - but i cannot seem to solve this. I even tried a simple DTO that has the ienumerable as a property, but that ran into problems with 'needing a key'.
A lot of the research i've tried leads me down to this path:
https://github.com/OData/WebApi/issues/1873
That isnt quite the same, becuase thats looking for a header and Im trying to use a body.
Is there an actual workaround to this?

How can I implement multiple forms using a single view?

I am having a scenario where I need to implement two forms using a single view... There will be a home page having a form each for LogIn and SignUp (similar to Facebook homepage). I created a view for my home page (Index.cshtml) that contains the razor code for both my forms.
[#using (Html.BeginForm("LogIn", "Home", FormMethod.Post))]
[#using (Html.BeginForm("SignUp", "Home", FormMethod.Post))]
However, upon clicking the 'Log In' button for LogIn form or clicking 'Sign Up' button for SignUp form, the runtime throws an error basically saying that I still need to create views for both LogIn and SignUp actions, even though I have already implemented the HTML forms in my index.cshtml
[NOTE: I am not using ASP.NET membership provider. And this question is generally for two forms, can be any two forms.]
So my question is: Do I really need to create two more views named LogIn.cshtml and SignUp.cshtml? Won't this cause code duplication? I'm quite new to MVC 4 and I hope you understand what I'm trying to do here, so all I want to know is whether there is any other way to implement this? (jQuery, AJAX or something)
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpGet]
public ActionResult LogIn()
{
return View();
}
[HttpPost]
public ActionResult LogIn(Account acc)
{
// some code
return View();
}
[HttpGet]
public ActionResult SignUp()
{
return View();
}
[HttpPost]
public ActionResult SignUp(Account acc)
{
// some code
return View();
}
}
You could specify the view you want to be returned:
[HttpGet]
public ActionResult SignUp()
{
return View("LogIn");
}