0

I am new to asp.net MVC, I am making one project just like stack overflow. In this, I just want to use the ajax system to upvote or down-vote the answer. So, I can show the counter increase and decrease without refreshing the page. I have default scaffolding one controller of Question in the controller and in which I have QuitionDetails method which is responsible for the QuitionDetailsView and in this view I am making ajax request to my API controller VotesController when the user clicks on the up-vote or down-vote. But I am getting this error

jquery-3.3.1.js:9600 PUT https://localhost:44389/Question/QuestionDetails/api/votes/3 404 not found
send @ jquery-3.3.1.js:9600
ajax @ jquery-3.3.1.js:9206
(anonymous) @ 2:230
dispatch @ jquery-3.3.1.js:5183
elemData.handle @ jquery-3.3.1.js:4991

here is my first default scaffolding controller Question

public ActionResult QuestionDetails(int Id)
        {
            QuestionDetailViewModel questionDetailViewModel = new QuestionDetailViewModel
            {
                Question = QBL.GetQuestions(Id),
                UserId = User.Identity.GetUserId(),
                QuestionId = Id,
            };
            return View(questionDetailViewModel);
        }
        [HttpPost]
        [ValidateInput(false)]
        public ActionResult QuestionDetails(QuestionDetailViewModel questionDetailViewModel)
        {
            QBL.CreateAnswer(questionDetailViewModel);
            return RedirectToAction("QuestionDetails", new { Id = questionDetailViewModel.QuestionId });
        }

View Code is as Below

@model AskMe.Models.ViewModel.QuestionDetailViewModel

@{
    ViewBag.Title = "QuestionDetails";
}

<h1>Question Details: </h1>
<h3>@Model.Question.Post.Title</h3>
@Html.Raw(Model.Question.Post.Content)
<hr />
<h3>Answers:</h3>
@foreach (var answer in Model.Question.Answers)
{
    <div class="card bg-light m-1">
        <div class="card-body">
            <h5 class="card-title">Answered by: @answer.Post.CreatedBy.UserName</h5>
            @Html.Raw(answer.Post.Content)
        </div>
        <div id="vote" class="col">
            <div>
                <button data-vote-id="@answer.Post.PostId" class="nav-link thumbs-up" href=""><i class="fa fa-thumbs-up" aria-hidden="true"></i></button>
            </div>
            <div>

            </div>
            <div>
                <button data-vote-id="@answer.Post.PostId" class="nav-link thumbs-down" href=""><i class="fa fa-thumbs-down" aria-hidden="true"></i></button>
            </div>
        </div>
    </div>
}
@using (Html.BeginForm())
{

    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h3>Contribute your answer: </h3>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

        <div class="form-group">
            @Html.LabelFor(m => m.AnswerContent, new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.TextAreaFor(m => m.AnswerContent, new { @class = "form-control" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                @Html.HiddenFor(m => m.UserId)
                @Html.HiddenFor(m => m.QuestionId)
                <input type="submit" value="Contribute now" class="btn btn-outline-primary" />
            </div>
        </div>
    </div>
}
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval");

    <script type="text/javascript">
        $(document).ready(function () {
            tinyMCE.init({
                mode: "textareas",
            });

            $("#vote").on("click",".thumbs-up", function () {
                console.log("in selection func");
                $.ajax({                   
                url: "api/vote/" + $(this).attr("data-vote-id"),
                method: "PUT",
                success: function () {
                    console.log("success");
                }
            })
        })

        });
    </script>

}

And here is my votes API controller code

using AskMe.Models;
using Microsoft.AspNet.Identity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace AskMe.API
{
    public class VotesController : ApiController
    {
        ApplicationDbContext _context = new ApplicationDbContext();

        [HttpPut]
        public IHttpActionResult UpVote(int postId)
        {
            var userId = User.Identity.GetUserId();
            var user = _context.Users.Find(userId);
            var post = _context.Posts.Find(postId);
            var votes = post.Votes.ToList();
            if (votes.FindAll(u => u.UserId == userId).Count == 0)
            {
                Votes vote = new Votes
                {
                    VotedDateTime = DateTime.Now,
                    UserId = userId,
                    User = user,
                    Post = post,
                    PostId = postId,
                };
                post.Votes.Add(vote);
                _context.SaveChanges();
                return Ok();
            }
            return BadRequest();
        }
    }
}

I am not sure my api link should be like this https://localhost:44389/Question/QuestionDetails/api/votes/3 or https://localhost:44389/api/votes/3 and my route config is routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } );

Abhi
  • 1
  • 1
  • Given you're using an `ApiController` this seems to be a WebAPI issue, not MVC. Secondly, what is your routing structure? If it's the default you should be using something like this: `PUT https://localhost:44389/api/votes/upvote/3` – Rory McCrossan Nov 20 '19 at 11:21
  • Hi, I did the route as per the suggestion now and still, I am getting an error `jquery-3.3.1.js:9600 PUT https://localhost:44389/Question/QuestionDetails/API/Votes/UpVote/3 404` – Abhi Nov 20 '19 at 12:04
  • That was not my suggestion. That's an MVC route, yet you're using WebAPI. – Rory McCrossan Nov 20 '19 at 12:05
  • Ok, I got your point but I am still not able to understand where am I making mistake in web API. – Abhi Nov 20 '19 at 12:13
  • I mean why my route has `https://localhost:44389/Question/QuestionDetails/` before `/API/Votes/UpVote/3` why not `https://localhost:44389/api/votes/upvote/3` – Abhi Nov 20 '19 at 12:17

2 Answers2

1

If you haven't changed the standard routing, you need to include the action/method name in your ajax call.

Try:

url: "api/vote/upvote/" + $(this).attr("data-vote-id")

Your route configuration should look like this:

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

If you are using MVC5 with WebApi, which is my guess, you have to be careful. See this post for further information on how to do it.

bdongus
  • 658
  • 4
  • 20
  • If i'm wrong please let me know, but api controller name is "votes" right. Than url should be `url: "api/votes/upvote/" + $(this).attr("data-vote-id")` – Erdem Ozdemir Nov 20 '19 at 11:48
  • Hi, I got your point and corrected my mistake the route as per the suggestion now and still, I am getting an error `jquery-3.3.1.js:9600 PUT https://localhost:44389/Question/QuestionDetails/API/Votes/UpVote/3 404 – ` and my route config is as follow ```routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } );``` – Abhi Nov 20 '19 at 12:10
  • I updated my answer. Your route config is the MVC configuration. Are you using MVC5? – bdongus Nov 20 '19 at 13:06
  • If that helped you please mark it as answer. Thank you. – bdongus Nov 20 '19 at 14:40
0

Actually your error telling everything. When you requesting for 'UpVote' action it's looking into "basepath(localhost)/controller/action/Api/etc." and it does not exits. You must create request for https://localhost:44389/API/Votes/UpVote/3

Erdem Ozdemir
  • 91
  • 1
  • 6