0

I have 2 tables(student and parent) into which I wanna post the data. I have a MVC controller and an API controller. I am trying to route createStudent(StudentViewModel student) action method in mvc controller to PostStudent(StudentViewModel student) in API controller and createParent(ParentViewModel p) to PostParent(ParentViewModel p) respectively. But having two post methods in API controller makes it ambiguous.

I am not able to find a way to use two post methods in same api controller through mvc controller.

This is my code in MVC Controller(named StudentController)

 public ActionResult createStudent()
    {
        return View();
    }

[System.Web.Mvc.HttpPost]
public ActionResult createStudent(StudentViewModel student)
{
    using (var client = new HttpClient())
    {
        client.BaseAddress = new Uri("http://localhost:39673/api/student");

        var postTask = client.PostAsJsonAsync<StudentViewModel>("student", student);
        postTask.Wait();

        var result = postTask.Result;
        if (result.IsSuccessStatusCode)
        {
           return RedirectToAction("Index");
        }
    }

    ModelState.AddModelError(string.Empty, "Server Error. Please contact administrator.");

    return View(student);
}

public ActionResult createparent()
{
    return View();
}

[System.Web.Mvc.HttpPost]
public ActionResult createparent(ParentViewModel p)
{
    using (var client = new HttpClient())
    {
        client.BaseAddress = new Uri("http://localhost:39673/api/Student");

        //HTTP POST
        var postTask = client.PostAsJsonAsync<ParentViewModel>("parent", p);
        postTask.Wait();

        var result = postTask.Result;
        if (result.IsSuccessStatusCode)
        {
            return View();
        }
    }

    ModelState.AddModelError(string.Empty, "Server Error. Please contact administrator.");

    return View(p);
}

This is my API Controller(named StudentController)

    public class StudentController : ApiController
    {
        //POST Student
        public IHttpActionResult PostStudent(StudentViewModel student)
        {
            if (!ModelState.IsValid)
                return BadRequest("Invalid data.");

            using (var ctx = new MyEntities())
            {
                ctx.Students.Add(new Student()
                {
                    Name = student.Name,
                    MobileNO = student.MobileNO
                });

                ctx.SaveChanges();
            }

            return Ok();
        }

//POST Parent
public IHttpActionResult PostParent(ParentViewModel p)
        {
            if (!ModelState.IsValid)
                return BadRequest("Invalid data.");

            using (var ctx = new MyEntities())
            {
                ctx.Parents.Add(new Parent()
                {
                    StudentID=p.StudentID,
                    ParentName = p.ParentName,
                });

                ctx.SaveChanges();
            }

            return Ok();
        }
    }

Thanks

1 Answers1

0

With the default route definition for registering the api endpoints, you will access the endpoints with the format api/controllername. Basically you will access the methods in that with the combination of method signature (primary parameters) and the Http verb (GET/POST). So you should have only one POST method for your resource (student/parent)

I recommend you create one api controller for Student and one for Parent. Each can have it's own Post method.

public class StudentController : ApiController
{
    [HttpPost]
    public IHttpActionResult Post(StudentViewModel student)
    {
       return Ok();
    }
}
public class ParentController : ApiController
{
    [HttpPost]
    public IHttpActionResult Post(ParentViewModel parent)
    {
       return Ok();
    }
}

Now call this /api/student and /api/parent with HttpPost method.

Another option is to explicitly give route template to your methods in the same controller.

public class StudentController : ApiController
{
    [HttpPost]
    [Route("api/student/")]
    public IHttpActionResult PostStudent(StudentViewModel  student)
    {
        return Ok();
    }

    [HttpPost]
    [Route("api/parent/")]
    public IHttpActionResult PostParent(ParentViewModel p)
    {
        return Ok();
    }
}

Now call this /api/student and /api/parent with HttpPost method. While this works, i personally prefer to go with the first approach, one api controller for a resource. that looks much clean to me :)

Also, looking at your code, it looks like you are calling the web api controller from the mvc controller. If your mvc controllers and web api controllers are in the same project, instead of making an http call , why not call a common helper method which does it for you ? You can call the same common helper from both your web api controller and your mvc controller ,so that your save code is only at a single place.

Also, you should try to async and await all the way down to prevent deadlocks.

Take a look at this post await vs Task.Wait - Deadlock?

Shyju
  • 214,206
  • 104
  • 411
  • 497