Non è stata rilevata alcuna risorsa HTTP che corrisponde all'errore di richiesta URI nell'API Web ASP.NET

StackOverflow https://stackoverflow.com//questions/23013509

Domanda

Questo è uno schizzo della mia classe di transfercontroller.

Tutto questo è il codice API Web.

public class TransferController : ApiController
{
  [HttpGet, ActionName("Queue")]
  public IEnumerable<object> GetQueue(Guid sessionId) {...}

  [HttpDelete, ActionName("Delete")]
  public void Delete(Guid sessionId, Guid fileId) {...}

  [HttpGet, ActionName("Cancel")]
  public bool Cancel(Guid sessionId, Guid fileId) {...}

  [HttpGet, ActionName("UploadedBytes")]
  public long GetUploadedByteCount(Guid sessionId, Guid fileId) {...}

  [HttpGet, ActionName("DownloadUrl")]
  public string GetDownloadUrl(string fileId) {...}

  [HttpPost, ActionName("FileChunk")] 
  public void PostFileChunk([FromUri]Guid sessionId, [FromUri]Guid fileId) {...}

  [HttpPost, ActionName("UploadDefinition")]
  public Guid PostUploadItem([FromBody]UploadDefinition uploadDef) {...}

}
.

Questo è il routing.

public static void Register(HttpConfiguration config)
{
  config.Routes.MapHttpRoute(
    name: "DefaultApi", 
    routeTemplate: "api/{controller}/{action}"
    );
  config.Routes.MapHttpRoute(
    name: "DefaultApiDefaultMethod", 
    routeTemplate: "api/{controller}"
    );
}
.

Questa è l'invocazione.

$.ajax({
  url: "api/Transfer/Queue",
  data: { sessiondId: login.SessionId() }    
})
.done(function (result) {
  history.push(new UploadItem());
  for (var i = 0; i < result.length; i++) {
    var ui = new UploadItem(result[i]);
    history.push(ui);
  }
})
.fail(function (result) {
  app.showMessage(JSON.parse(result.responseText).Message);
});
.

E questo è il risultato.

No HTTP resource was found that matches the request URI 'http://localhost:54770/api/Transfer/Queue?sessiondId=0e2c47b9-e674-446d-a06c-ce16932f9580'.

Questo è uno schizzo della mia classe USController.

public class UserController : ApiController 

  [HttpGet, ActionName("Authenticate")]
  public object Authenticate(string email, string password) {...}

  [HttpPost]
  public void Register([FromBody]UserDefinition userDef) {...}

  [HttpGet, ActionName("Pulse")]
  public bool Pulse(Guid sessionId) {...}

}
.

Per ragioni insondabili per me, non ho problemi a chiamare nulla nell'UserController. I parametri sono marshalling esattamente nello stesso modo, e le vie STUSS sono in uso.


.

Darrel Miller sottostante utilizza il test dell'unità per convalidare i percorsi. Francamente mi sto prendendo a calci per non pensare a questo, e ora ho fatto lo stesso.

Ma i test mentre li mostra davvero testare solo l'analisi dell'URL. Ad esempio, questo test passa

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


  var route =
      config.Routes.GetRouteData(new HttpRequestMessage()
      {
        RequestUri = new Uri("http://localhost:54770/api/Transfer/Wibble?sessionId=0e2c47b9-e674-446d-a06c-ce16932f9580&fileId=0e2c47b9-e674-446d-a06c-ce16932f9581")  //?
      });

  Assert.IsNotNull(route);
  Assert.AreEqual("Transfer", route.Values["controller"]);
  Assert.AreEqual("Wibble", route.Values["action"]);

}
.

Nonostante la cospicua assenza di un metodo wibble sul controller di trasferimento.

Anche l'oggetto percorso non è in realtà un oggetto httproute, è un oggetto httproutedata. Ma è correttamente corretto. L'oggetto httproute è disponibile come proprietà dell'oggetto httproutedata.

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


  var routeData =
      config.Routes.GetRouteData(new HttpRequestMessage()
      {
        RequestUri = new Uri("http://localhost:54770/api/Transfer/Wibble?sessionId=0e2c47b9-e674-446d-a06c-ce16932f9580&fileId=0e2c47b9-e674-446d-a06c-ce16932f9581")  //?
      });

  Assert.IsNotNull(routeData);
  Assert.AreEqual("Transfer", routeData.Values["controller"]);
  Assert.AreEqual("Wibble", routeData.Values["action"]);

}
.

E a sua volta ha una proprietà del gestore. Tuttavia questo è meno informativo di quanto potrebbe essere, poiché un gestore null significa semplicemente (da MSDN)

.

Se NULL, il gestore predefinito invia messaggi alle implementazioni di IHTTPController.

Ora, il mio controller deriva da Apicontroller che implementa sicuramente il metodo ExecutAsync che è l'unica cosa specificata dall'interfaccia IHTTPController. Che immagino significa che potrei testare l'esecuzione di quel metodo se ne sapessi di più.

È stato utile?

Soluzione 2

Ok allora ... Grazie per aver messo l'idea del test dell'unità nella mia testa, ha spinto le cose immensamente.

Ecco il Lowdown:

È possibile avere firme di parametri identici su verbi diversi (ottenere post put cancellazione).

You Impossibile ha una firma dei parametri identici su nomi di azioni diversi sullo stesso verbo.

Hai solo bisogno di Vary one Nome del parametro.

Quindi questo è ok perché sono tutti su verbi diversi

[HttpDelete, ActionName("Delete")]
public void Delete(Guid sessionId, Guid fileId) {...}

[HttpGet, ActionName("Cancel")]
public bool Cancel(Guid sessionId, Guid fileId) {...}

[HttpPost, ActionName("FileChunk")] 
public void PostFileChunk(Guid sessionId, Guid fileId) {...}
.

Ma questo non è bello perché entrambi vengono

[HttpGet, ActionName("UploadedBytes")]
public long GetUploadedByteCount(Guid sessionId, Guid fileId) {...}

[HttpGet, ActionName("Cancel")]
public bool Cancel(Guid sessionId, Guid fileId) {...}
.

E puoi sistemarlo come questo

[HttpGet, ActionName("UploadedBytes")]
public long GetUploadedByteCount(Guid sessionId, Guid uploadBytesFileId) {...}

[HttpGet, ActionName("Cancel")]
public bool Cancel(Guid sessionId, Guid cancelFileId) {...}
.

Forse sono un duro culo ma per quanto mi riguarda non è instradato finché non viene chiamato il metodo.

Altri suggerimenti

Ecco un test che dimostra il routing funziona bene,

[Fact]
public void TestRoute() 
{
    var config = new HttpConfiguration();
    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{action}"
        );


    var route =
        config.Routes.GetRouteData(new HttpRequestMessage()
        {
            RequestUri = new Uri("http://localhost:54770/api/Transfer/Queue?sessionId=0e2c47b9-e674-446d-a06c-ce16932f9580")  //?
        });

    Assert.NotNull(route);
    Assert.Equal("Transfer",route.Values["controller"]);
    Assert.Equal("Queue",route.Values["action"]);

}
.

Ed ecco un test che mostra la selezione di dispacciamento / azione anche funziona,

[Fact]
public void TestDispatch()
{
    var config = new HttpConfiguration();
    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{action}"
        );

    var server = new HttpServer(config);

    var client = new HttpClient(server);
    var response =
        client.GetAsync(new Uri("http://localhost:54770/api/Transfer/Queue?sessionId=0e2c47b9-e674-446d-a06c-ce16932f9580")) // 
            .Result;

    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}


public class TransferController : ApiController
{
   [HttpGet]
   [ActionName("Queue")]
   public IEnumerable<object> Queue(Guid sessionId) 
   {
       return null;
   }

}
.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top