0

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}"

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

If I do like [Route("api/px/oper/{pid:Guid}")] and removing [ActionName] from ById(Guid personid) to ById(Guid pid), it works. But why it is not matching the route? I also was not successful using Route Debugger. It was not even working.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.