Mert Gülsoy
Mert Gülsoy

Reputation: 2919

Asp.Net Web Api 2 Strange Routing Behaviour

I am using vs2012 and started a new project with "ASP.net Web Api 2" template. Finished coding and started to test the system. I observe strange behaviour with routing. Such as:

Here are my routes:

config.Routes.MapHttpRoute(
    name: "personRoute",
    routeTemplate: "api/px/{action}/{personid:Guid}",
    defaults: new { controller = "px", personid = RouteParameter.Optional }
);

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

and here is my controller:

public class PxController : ApiController {

    private Configuration.DatabaseContext dbctx = new Configuration.DatabaseContext();

    [HttpGet]
    public IEnumerable<Models.Person> GetAll() {
        return dbctx.Persons.ToArray();
    }

    [ActionName( "op" )]
    [HttpGet]
    public Models.Person ById( Guid personid ) {
        var data = dbctx.Persons.FirstOrDefault( e => e.PersonId == personid );

        if (data == null) {
            throw new HttpResponseException( HttpStatusCode.NotFound );
        }

        return data;
    }

    [ActionName( "op" )]
    [HttpPost]
    public void Insert( [FromBody] Models.Person newPerson ) {
        dbctx.Persons.Add( newPerson );           
        dbctx.SaveChanges();  
    }

    [ActionName( "op" )]
    [HttpPut]
    public void Update( [FromBody]Models.Person eperson ) {          
        var data = dbctx.Persons.FirstOrDefault( e => e.PersonId == eperson.PersonId );

        if (data == null) {
            throw new HttpResponseException( HttpStatusCode.NotFound );
        }

        dbctx.Entry( eperson ).State = System.Data.Entity.EntityState.Modified;
        dbctx.SaveChanges();
    }

    [ActionName( "op" )]
    [HttpDelete]
    public void DeleteById( Guid personid ) {
        var data = dbctx.Persons.FirstOrDefault( e => e.PersonId == personid );

        if (data == null) {
            throw new HttpResponseException( HttpStatusCode.NotFound );
        }

        dbctx.Entry( data ).State = System.Data.Entity.EntityState.Deleted;
        dbctx.SaveChanges();
    }

    #region |:.Extended Queries.:|
    [HttpGet]
    public IEnumerable<RemoteProperty> Properties( Guid personid ) {
        var data = from n in dbctx.RemoteProperties
                   where n.PersonId == personid && n.ParentId == null
                   orderby n.PropertyType.Name
                   select n;

        if (data == null)
            throw new HttpResponseException( HttpStatusCode.NotFound );

        foreach (var rp in data) {
            rp.Details = dbctx.RemoteProperties.SqlQuery( "SELECT * FROM properties WHERE parentid = @parid" ).ToArray();
        }

        return data.ToArray();
    }

    [HttpGet]
    public IEnumerable<Relation> Relations( Guid personid ) {
        var data = from n in dbctx.Relations
                   where n.PersonId == personid
                   select n;

        if (data == null)
            throw new HttpResponseException( HttpStatusCode.NotFound );

        return data.ToArray();
    }
    #endregion

    [NonAction]
    protected override void Dispose( bool disposing ) {

        if (dbctx != null && dbctx is IDisposable) {
            dbctx.Dispose();
        }

        base.Dispose( disposing );
    }

}

These are the Fiddler outputs for the queries:

http://localhost:49318/api/px/GetAll
/* Works as expected */

http://localhost:49318/api/px/op/dfc737ca-312c-e411-ae3c-78843ccba6ef
/* The requested resource does not support http method 'GET'. */

http://localhost:49318/api/px/op?personid=dfc737ca-312c-e411-ae3c-78843ccba6ef
/* Returns the data with personid, but why the above query fails? */

http://localhost:49318/api/px/properties?personid=dfc737ca-312c-e411-ae3c-78843ccba6ef
/* Returns the data with personid */

http://localhost:49318/api/px/properties/dfc737ca-312c-e411-ae3c-78843ccba6ef
/* No action was found on the controller 'Px' that matches the request */

My question is what could be the reason for this behaviour? I also cannot use routes like (because they are not working):

"api/{controller}/{personid}/{action}"

Upvotes: 0

Views: 262

Answers (2)

Mert G&#252;lsoy
Mert G&#252;lsoy

Reputation: 2919

Ok. By examining the whole project and applying the changes (listed below), I successfully managed to have it worked. So here is what I did:

  • I was using VS2012 and web.api template 2.0 and .net 4.5.
  • The web.api 2.0 is not supported on VS2012 but with an update.
  • I've checked all DLL file references an realized that some of them have wrong versions.
  • Thus I deleted all references.
  • I get Web.api 2.2 from NuGet and installed all DLL files
  • Voila. It started to work.

For debugging the project, there is a "trace" assembly which MS provided, I used it. It puts trace messages to output window what is being done while routing and more. So I was able to see what is (was) happening. VS 2012 update is not enough to make it work.

Upvotes: 0

Aaron Havens
Aaron Havens

Reputation: 313

Try using the [Route] Attribute instead of the [Action] attribute.

On my controllers I have been successfully using the following:

[RoutePrefix("api/Demo")] // Sets the base route for actions in this controller
public class DemoController : ApiController
{
    [HttpGet]
    [Route("DemoAction")] // This makes this function map to route http://site/api/Demo/DemoAction
    public IHttpActionResult PerformComplexApiAction(int id)
    {
        ...

The [RoutePrefix] can be omitted and the full route can be provided in the individual [Route] entry on each function.

Upvotes: 1

Related Questions