onmyway
onmyway

Reputation: 1515

AngularJS Controller not finding C# Controller

I hope you guys can help me.

I have a simple project still in its infancy, but cannot get the AngularJS Controller (ingredientAdmin.controller) to find my C# API controller.

I get an Error: 404 / Not Found: Request URL: http://localhost:31021/api/ingredientAdmin/PostIngredient/

My AngularJS controller and C# controller is in different projects, and I have referenced my C# controller project in my AngularJS project.

I have also tried various spellings etc., but think I might be missing something.

Here is my AngularJS controller: ingredientAdminController:

(function () {
    "use strict";
    var controllerId = 'admin';

    angular
        .module('app.ingredientAdmin')
        .controller('ingredientAdminController', ingredientAdminController, controllerId);

    ingredientAdminController.$inject = ['$http', '$scope', 'common'];

    function ingredientAdminController($http, $scope, common) {
        var vm = $scope;
        vm.formSubmmision = true;
        vm.title = 'Ingredients Admin';
        vm.ingredientData = null;
        vm.save = save;

        var getLogFn = common.logger.getLogFn;
        var log = getLogFn(controllerId);

        activate();

        function activate() {
            common.activateController([], controllerId)
                .then(function () { log('Activated Admin View'); });
        }

        // Save

        function save() {
            if (vm.formIngredientsAdmin.$valid) {
                postNewData();
            }
            else {
                logger.error('Error: Validation failed. Please correct data and try again');
                vm.formSubmmision = false;
            }
        }

        function postNewData() {
            //prepare data 
            var data = {
                IngredientId: 0,
                IngredientName: vm.NewIngredient.IngredientName,
                IngredientDescription: vm.NewIngredient.IngredientDescription
            }


            $http.post('/api/ingredientAdmin/PostIngredient/', data)
                .then(postDataComplete)
                .catch(getDataFailed);

            function postDataComplete(response) {
                vm.NewIngredient = null;
                vm.formSubmmision = true;
                vm.formIngredientsAdmin.$setPristine();
                vm.formIngredientsAdmin.$setUntouched();
                return vm.NewIngredient;
            }

            function getDataFailed(error) {
                log('Failed to create new Ingredient ' + error.data.Message);
                return;
            }

        }


    };


}
)();

Here is my C# controller: IngredientAdminController:

using System.Net;
using System.Net.Http;
using System.Web.Http;
using RecipeManager.Models;
using RecipeManager.DTO;
using RecipeManger.Common;

namespace RecipeManager.Controllers.Api
{
    public class IngredientAdminController : ApiController
    {
        private RecipeManager.DTO.IngredientAdminDTO dto = new IngredientAdminDTO();

        [HttpPost]
        public HttpResponseMessage PostIngredient(Ingredient ingredient)
        {
            try
            {
                CommandResult<Ingredient> result = dto.CreateIngredient(ingredient);
                return Request.CreateResponse(HttpStatusCode.OK, result);

            }
            catch (RecipeManagerException ex)
            {
                return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
            }
        }

        //[Authorize(Roles = "Admin, SupportCallIndex")]
        public HttpResponseMessage UpdateIngredient(Ingredient ingredient)
        {
            try
            {
                CommandResult<Ingredient> result = dto.UpdateIngredient(ingredient);
                return Request.CreateResponse(HttpStatusCode.OK, result);
            }
            catch (RecipeManagerException ex)
            {
                return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
            }
        }

        [HttpPost]
        //[Authorize(Roles = "Admin, SupportCallIndex")]
        public HttpResponseMessage DeleteIngredient(Ingredient ingredient)
        {
            try
            {
                CommandResult<Ingredient> result = dto.DeleteIngredient(ingredient);
                return Request.CreateResponse(HttpStatusCode.OK, result);
            }
            catch (RecipeManagerException ex)
            {
                return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
            }
        }

        public HttpResponseMessage GetAll()
        {
            try
            {
                CommandResult<Ingredient> result = dto.ReadIngredient();
                return Request.CreateResponse((result.Status == CommandStatus.Success ? HttpStatusCode.OK : HttpStatusCode.InternalServerError), result);
            }
            catch (RecipeManagerException ex)
            {
                return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
            }
        }


    }
}

Here is my WebApiConfig code:

using System.Web.Http;
using Microsoft.Owin.Security.OAuth;

namespace RecipeManager.UI.Htmll5
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {

            config.MapHttpAttributeRoutes();

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

This is the structure of my app skeleton:

App Layout

Thank you greatly!

Upvotes: 1

Views: 1156

Answers (3)

Uladz Kha
Uladz Kha

Reputation: 2364

You can add RoutePrefix and Route into your controller:

[RoutePrefix("api")]

    public class IngredientAdminController : ApiController
        {
            private RecipeManager.DTO.IngredientAdminDTO dto = new IngredientAdminDTO();

        [Route("PostIngredient")]
        [HttpPost]

        public HttpResponseMessage PostIngredient(Ingredient ingredient)
        {
            try
            {
                CommandResult<Ingredient> result = dto.CreateIngredient(ingredient);
                return Request.CreateResponse(HttpStatusCode.OK, result);

            }
            catch (RecipeManagerException ex)
            {
                return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
            }
        }

And your request:

var req = {
method: 'POST',
url: '/api/PostIngredient',
data: data
};

$http(req).then(function successCallback(responseSuccess) {

                        }, function errorCallback(responseError) {

                        });

hope it help.

Upvotes: 1

Ric
Ric

Reputation: 13248

If you want to keep your code as it currently is, then add this route before the default:

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

as mentioned by @Lex, added defaults for id param.

Upvotes: 2

granadaCoder
granadaCoder

Reputation: 27874

WebApi / HttpPost has a few weird caveats about it.

See my answer (not question, but my answer) here:

Web api not supporting POST method

Note the Method on the Api Controller:

  [System.Web.Http.HttpPost]
    public MyOutputObject DoSomething([FromBody]MyInputObject args)
    {
        Console.Writeline(args.ToString());
    }

Please note this article:

http://www.dontpaniclabs.com/blog/post/2013/01/23/That-Pesky-Requested-Resource-Does-Not-Support-HTTP-Method-POST-Error-When-Using-MVC-Web-API/

and this article

http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/

Upvotes: 1

Related Questions