21

パスでピリオドを使用している生の http ハンドラーから API プロジェクトを移動する作業を行っています。

http://server/collection/id.format

Web Api (自己ホスト) バージョンで同じ URL スキーマに従いたいと思い、これを試しました:

var c = new HttpSelfHostConfiguration(b);
c.Routes.MapHttpRoute(
    name: "DefaultApiRoute",
    routeTemplate: "{controller}/{id}.{format}",
    defaults: new { id = RouteParameter.Optional, format = RouteParameter.Optional },
    constraints: null
);

残念ながら、それは解決していないようです (/foo、/foo/bar、および /foo/bar.txt で一貫した 404 です)。「format」の前にスラッシュを使用した同様のパターンは正常に機能します。

var c = new HttpSelfHostConfiguration(b);
c.Routes.MapHttpRoute(
    name: "DefaultApiRoute",
    routeTemplate: "{controller}/{id}/{format}",
    defaults: new { id = RouteParameter.Optional, format = RouteParameter.Optional },
    constraints: null
);

私はまだ Web Api のコードを掘り下げていません。その前に、これが Web Api の既知の制限であるか、または正当な制限であるかどうかを確認するために、ここで質問したいと思います。

更新:「id」と「format」は文字列であることに言及するのを怠りました。これは、この質問の解決に重要であることが判明しました。「id」トークンからピリオドを除外する制約を追加すると、404 問題が解決します。

4

5 に答える 5

29

以下を実行することでこれを達成できました: web.config の system.webServer.handlers を置き換えます。つまり、ピリオドを削除し"*."ます。"*"

<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
于 2013-11-09T00:07:11.497 に答える
17

web.config の modules 属性に runAllManagedModulesForAllRequests オプションを設定するように注意してください

<modules runAllManagedModulesForAllRequests="true">..</modules>

そうしないと、IIS では機能しません (おそらく、管理されていないハンドラーによって処理されます)。

于 2012-07-31T11:35:09.033 に答える
16

I am unable to reproduce the problem. This should work. Here's my setup:

  1. Create a new .NET 4.0 Console Application
  2. Switch to .NET Framework 4.0 profile
  3. Install the Microsoft.AspNet.WebApi.SelfHost NuGet
  4. Define a Product

    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    
  5. A corresponding API Controller:

    public class ProductsController : ApiController
    {
        public Product Get(int id)
        {
            return new Product
            {
                Id = id,
                Name = "prd " + id
            };
        }
    }
    
  6. And a host:

    class Program
    {
        static void Main(string[] args)
        {
            var config = new HttpSelfHostConfiguration("http://localhost:8080");
    
            config.Routes.MapHttpRoute(
                name: "DefaultApiRoute",
                routeTemplate: "{controller}/{id}.{format}",
                defaults: new { id = RouteParameter.Optional, format = RouteParameter.Optional },
                constraints: null
            );
    
            using (var server = new HttpSelfHostServer(config))
            {
                server.OpenAsync().Wait();
                Console.WriteLine("Press Enter to quit.");
                Console.ReadLine();
            }
        }
    }
    

Now when you run this console application you could navigate to http://localhost:8080/products/123.xml. But of course you could navigate to http://localhost:8080/products/123.json and you will still get XML. So the question is: How to enable content negotiation using a route parameter?

You could do the following:

    class Program
    {
        static void Main(string[] args)
        {
            var config = new HttpSelfHostConfiguration("http://localhost:8080");
            config.Formatters.XmlFormatter.AddUriPathExtensionMapping("xml", "text/html");
            config.Formatters.JsonFormatter.AddUriPathExtensionMapping("json", "application/json");

            config.Routes.MapHttpRoute(
                name: "DefaultApiRoute",
                routeTemplate: "{controller}/{id}.{ext}",
                defaults: new { id = RouteParameter.Optional, formatter = RouteParameter.Optional },
                constraints: null
            );

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

and now you can use the following urls:

http://localhost:8080/products/123.xml
http://localhost:8080/products/123.json

Now you might be wondering what's the relation between the {ext} route parameter that we used in our route definition and the AddUriPathExtensionMapping method because nowhere we did not specify it. Well, guess what: it's hardcoded in the UriPathExtensionMapping class to ext and you cannot modify it because it is readonly:

public class UriPathExtensionMapping
{
    public static readonly string UriPathExtensionKey;

    static UriPathExtensionMapping()
    {
        UriPathExtensionKey = "ext";
    }

    ...
}

All this to answer your question:

Can periods be used in Asp.Net Web Api Routes?

Yes.

于 2012-07-15T18:54:37.863 に答える
12

Darin の回答を受け入れます (はい、ルートの URL にピリオドを使用できます)。これは、「id」が整数ではなく文字列であることを明確に示さなかった私のせいです。

文字列パラメーターの後にピリオドを使用するには、ルーティング エンジンは制約の形式でヒントを必要とします。

var c = new HttpSelfHostConfiguration(b);
c.Routes.MapHttpRoute(
    name: "DefaultApiRoute",
    routeTemplate: "{controller}/{id}.{format}",
    defaults: new { id = RouteParameter.Optional, format = RouteParameter.Optional },
    constraints: new { id = "[^\\.]+" } // anything but a period
);

前のトークンに制約を追加すると、インバウンド URL を正しく分解して処理できます。ヒントがない場合、「id」トークンは URL の残りの範囲と一致すると解釈できます。これは、一般的に文字列パラメーター間の境界を示すために制約が必要な特定のケースにすぎません。

はい、Asp.Net Web API の URL ルートでピリオドを使用できますが、ピリオドが文字列パラメーターに従う場合は、正しい制約をルートに適用してください。

于 2012-07-16T18:06:34.330 に答える