0

2012年9月12日更新:

私は自分のコードを同僚と共有しましたが、最初は何も変更せずにすべてが正常に機能しました。だから、私の箱には何か環境があるに違いない、誰か考えがありますか?

以下の更新を参照してください

設定:

.Net 4.5

セルフホスト(コンソールアプリ).Net 4.5WebAPIアプリケーション

MSTestを使用してハーネスをテストする

私のWebAPIアプリは、ほとんどがREST ApiControllerでいっぱいです。これらはすべて、標準のCRUDタイプのもので期待どおりに正しく機能します。これで、REST CRUDモデルにうまく適合しないように見える要件(内部キューにいくつかのオブジェクトを追加する)があります。この記事は、WebAPIでRPCスタイルの非REST操作を問題なく実行できると言っているようです。

私は次のような新しいコントローラーを作成しました。

public class TaskInstanceQueueController : ApiController
{
    public void Queue(TaskInstance taskInstance)
    {
        // Do something with my taskInstance
        Console.WriteLine("Method entered!");
    }
}

これを呼び出すプロキシクラスには、次のようなコードがあります。

public class TaskInstanceQueueProxy : ITaskInstanceQueueProxy
{
    readonly HttpClient _client = new HttpClient();

    public TaskInstanceQueueProxy()
    {
        var apiBaseUrl = System.Configuration.ConfigurationManager.AppSettings["APIBaseUrl"];
        _client.BaseAddress = new Uri(apiBaseUrl);
        _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    }

    public void QueueTaskInstances(TaskInstance taskInstance)
    {
        QueueTaskInstanceViaAPI(taskInstance);
    }

    private async void QueueTaskInstanceViaAPI(TaskInstance taskInstance)
    {

        var response = await _client.PostAsJsonAsync("api/TaskInstanceQueue/Queue", taskInstance);
        var msg = response.EnsureSuccessStatusCode();
    }

}

これが私のルートです:

    config.Routes.MapHttpRoute("API Default", "api/{controller}/{id}", new {id = RouteParameter.Optional});
    config.Routes.MapHttpRoute("API RPC Style", "api/{controller}/{action}", new { id = RouteParameter.Optional });

プロキシに対してテストを実行してもエラーは発生しませんが、コントローラーメソッド内でブレークポイントが発生することはなく、メソッドも入力されません。メッセージがコンソールに表示されます。varmsg行のブレークラインもヒットしません。何らかの理由で、これを行うためにHttpClientオブジェクトを適切に使用しているようには見えません。

繰り返しになりますが、このWeb APIアプリは、他の多くのAPIコントローラーで問題なく動作していますが、それらはすべて標準のREST処理を実行しています。

誰か手がかりがありますか?

アップデート

PostAsJsonAsync呼び出しの周りにtry/catchを置くと、次のようになります。

A first chance exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll
System.Threading.ThreadAbortException: Thread was being aborted.
   at System.Threading.Tasks.TaskHelpers.RunSynchronously(Action action, CancellationToken token)
   at System.Net.Http.Formatting.JsonMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext)
   at System.Net.Http.ObjectContent.SerializeToStreamAsync(Stream stream, TransportContext context)
   at System.Net.Http.HttpContent.LoadIntoBufferAsync(Int64 maxBufferSize)
   at System.Net.Http.HttpClientHandler.PrepareAndStartContentUpload(RequestState state)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at TaskManagerProxy.TaskInstanceQueueProxy.<QueueTaskInstanceViaAPI>d__0.MoveNext() in c:\Moso\MOSO\MOSO.Infrastructure\tm\TaskManagerProxy\TaskManagerProxy\TaskInstanceQueueProxy.cs:line 30

30行目は通話のある行です。

4

2 に答える 2

6

この答えは、で定義した他のメソッドの数によって異なりますTaskInstanceQueueController。キューがあなたの唯一のものであると仮定すると、私はあなたのルートがすでに機能していると信じています(それらは少し乱雑ですが)。

コードのサンプルバージョンを作成し、キューメソッドに正常に投稿し、FiddlerとCurlを使用してブレークポイントに到達することができました。私はあなたの例について少し詳しく説明し、RPCアクションを通常のRESTメソッドとどのように組み合わせることができるかを示しました。

サンプルコードはここのGitHubにあります。

基本的に、問題は特にWebApi要素(ルート、構成など)に関係するものではありませんが、最初の質問でサーバーの呼び出し方法が示唆されているため、オプションIDを削除してHttpPost属性をキューメソッドに追加する必要があります。これはおそらく別の質問になるはずです。

2つのプロジェクトがあるかどうか、MSテストコードがどのようにホストされているかなどは不明ですが、WebApi統合テストの良い例がここにあります。Fiddlerなどのツールを使用してAPIをデバッグすると、すぐに削除できます。ルーティング構成の問題をデバッグします。

作業コンソールプログラム:

static void Main(string[] args)
    {
       // Set up server configuration 
        HttpSelfHostConfiguration config = new HttpSelfHostConfiguration("http://localhost:8080");

        //Route Catches the GET PUT DELETE typical REST based interactions (add more if needed)
        config.Routes.MapHttpRoute("API Default", "api/{controller}/{id}",
            new { id = RouteParameter.Optional },
            new { httpMethod = new HttpMethodConstraint(HttpMethod.Get, HttpMethod.Put, HttpMethod.Delete) });

        //This allows POSTs to the RPC Style methods http://api/controller/action
        config.Routes.MapHttpRoute("API RPC Style", "api/{controller}/{action}",
            new { httpMethod = new HttpMethodConstraint(HttpMethod.Post) });

        //Finally this allows POST to typeical REST post address http://api/controller/
        config.Routes.MapHttpRoute("API Default 2", "api/{controller}/{action}",
            new { action = "Post" },
            new { httpMethod = new HttpMethodConstraint(HttpMethod.Post) });

        using (HttpSelfHostServer server = new HttpSelfHostServer(config))
        {
            server.OpenAsync().Wait();
            Console.WriteLine("Press Enter to quit.");
            Console.ReadLine();
        }
    }

ワーキングコントローラー

public class TaskInstanceQueueController : ApiController
{

     public void Get(string id)
    {
        // Do something with my taskInstance
        Console.WriteLine("Method entered!" + id);
    }

    [ActionName("Post")]
    [HttpPost]
    public void Post(TaskInstance taskInstance)
    {
        // Do something with my taskInstance
        Console.WriteLine("REST Post Method entered!");
    }

    [ActionName("Queue")]
    [HttpPost]
    public void Queue(TaskInstance taskInstance)
    {
        // Do something with my taskInstance
        Console.WriteLine("Queue Method entered!");
    }

    [ActionName("Another")]
    [HttpPost]
    public void Another(TaskInstance taskInstance)
    {
        Console.WriteLine("Another Method entered!");
    }
}
于 2012-09-12T08:14:28.717 に答える
4

あいまいなルートがあります。

config.Routes.MapHttpRoute("API Default", "api/{controller}/{id}", new {id = RouteParameter.Optional});
config.Routes.MapHttpRoute("API RPC Style", "api/{controller}/{action}", new { id = RouteParameter.Optional });

リクエストが/api/ TaskInstanceQueue / Queueに着信すると、最初のルートと一致するため、ルートデータには{controller = "TaskInstanceQueue"、id="Queue"}が含まれます。次に、システムはPostメソッドを検出しようとしますが、Post(またはPostXxx)メソッドがないため、HTTP呼び出しが失敗しているため、検出できません。

いくつかの選択肢があります。1つは、この1つのコントローラーに明示的なルート(最初)を配置できることです。

config.Routes.MapHttpRoute("API RPC Style", "api/TaskInstanceQueue/{action}", new { controller = "TaskInstanceQueue" });
config.Routes.MapHttpRoute("API Default", "api/{controller}/{id}", new {id = RouteParameter.Optional});

もう1つは、IDが常に数字のみであることがわかっている場合は、IDベースのルートに制約を追加できます。これにより、IDとしての「キュー」と一致しなくなり、正しいアクションに分類されます-ベースのルート。

于 2012-09-12T01:01:43.620 に答える