ユーザーが、2012年1月12日(2012年12月1日)などの英国形式でasp.netWebAPIコントローラーに日付を投稿できるようにしたいと思います。
私がデフォルトで言うことができることから、私たちのフォーマットだけが受け入れられます。
UKフォーマットがデフォルトになるようにどこかで何かを変更できますか?web.configでグローバリゼーション設定を変更しようとしましたが、効果がありませんでした。
ポール
ユーザーが、2012年1月12日(2012年12月1日)などの英国形式でasp.netWebAPIコントローラーに日付を投稿できるようにしたいと思います。
私がデフォルトで言うことができることから、私たちのフォーマットだけが受け入れられます。
UKフォーマットがデフォルトになるようにどこかで何かを変更できますか?web.configでグローバリゼーション設定を変更しようとしましたが、効果がありませんでした。
ポール
これは、MVC3のモデルバインダーとは少し異なるカスタムモデルバインダーを使用して行います。
public class DateTimeModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
var date = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).AttemptedValue;
if (String.IsNullOrEmpty(date))
return false;
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, bindingContext.ValueProvider.GetValue(bindingContext.ModelName));
try
{
bindingContext.Model = DateTime.Parse(date);
return true;
}
catch (Exception)
{
bindingContext.ModelState.AddModelError(bindingContext.ModelName, String.Format("\"{0}\" is invalid.", bindingContext.ModelName));
return false;
}
}
}
そして、私のGlobal.asax.csファイルに、次の行を追加して、DateTime値にこのモデルバインダーを使用するようにAPIに指示します。
GlobalConfiguration.Configuration.BindParameter(typeof(DateTime), new DateTimeModelBinder());
これが私のAPIコントローラーのメソッドです:
public IList<LeadsLeadRowViewModel> Get([ModelBinder]LeadsIndexViewModel inputModel)
私のLeadsIndexViewModelクラスにはいくつかのDateTimeプロパティがあり、これらはすべて有効な英国の日時になりました。
ええと、私もこれをグローバルレベルで解決したかったのです...そしてその過程でたくさんの髪を引き裂きました。WebApiには、受信フォームデータをインターセプトし、必要に応じて変更したい拡張ポイントがないことがわかりました。それはいいことではないでしょうか。それで、それだけが欠けていたので、WebApiのソースコードを可能な限り深く掘り下げて、何ができるかを調べました。結局、フォームデータの解析を担当するクラスを再利用してモデルを作成しました。特に日付を処理するために、ほんの数行を追加しました。以下のそのクラスは、次のように構成に追加できます。
private static void PlaceFormatterThatConvertsAllDatesToIsoFormat(HttpConfiguration config)
{
config.Formatters.Remove(
config.Formatters.FirstOrDefault(x => x is JQueryMvcFormUrlEncodedFormatter));
config.Formatters.Add(
new IsoDatesJQueryMvcFormUrlEncodedFormatter());
}
フォーマッター:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Threading.Tasks;
using System.Web.Http.ModelBinding;
namespace WebApi.Should.Allow.You.To.Set.The.Binder.Culture
{
// This class replaces WebApi's JQueryMvcFormUrlEncodedFormatter
// to support JQuery schema on FormURL. The reasong for this is that the
// supplied class was unreliable when parsing dates european style.
// So this is a painful workaround ...
/// <remarks>
/// Using this formatter any string that can be parsed as a date will be formatted using ISO format
/// </remarks>
public class IsoDatesJQueryMvcFormUrlEncodedFormatter : FormUrlEncodedMediaTypeFormatter
{
// we *are* in Israel
private static readonly CultureInfo israeliCulture = new CultureInfo("he-IL");
public override bool CanReadType(Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
return true;
}
public override Task<object> ReadFromStreamAsync(Type type
, Stream readStream
, HttpContent content
, IFormatterLogger formatterLogger)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
if (readStream == null)
{
throw new ArgumentNullException("readStream");
}
// For simple types, defer to base class
if (base.CanReadType(type))
{
return base.ReadFromStreamAsync(type, readStream, content, formatterLogger);
}
var result = base.ReadFromStreamAsync(
typeof(FormDataCollection),
readStream,
content,
formatterLogger);
Func<object, object> cultureSafeTask = (state) =>
{
var innterTask = (Task<object>)state;
var formDataCollection = (FormDataCollection)innterTask.Result;
var modifiedCollection = new List<KeyValuePair<string, string>>();
foreach (var item in formDataCollection)
{
DateTime date;
var isDate =
DateTime.TryParse(item.Value,
israeliCulture,
DateTimeStyles.AllowWhiteSpaces,
out date);
if (true == isDate)
{
modifiedCollection.Add(
new KeyValuePair<string, string>(
item.Key,
date.ToString("o")));
}
else
{
modifiedCollection.Add(
new KeyValuePair<string, string>(
item.Key,
item.Value));
}
}
formDataCollection = new FormDataCollection(modifiedCollection);
try
{
return
formDataCollection.ReadAs(type, String.Empty, RequiredMemberSelector, formatterLogger);
}
catch (Exception e)
{
if (formatterLogger == null)
{
throw;
}
formatterLogger.LogError(String.Empty, e);
return GetDefaultValueForType(type);
}
};
return
Task.Factory.StartNew(
cultureSafeTask
, result);
}
}
}
jQueryの日付ピッカーをen-gbにローカライズする例がここにあります:http ://weblogs.asp.net/hajan/archive/2010/10/05/integration-of-jquery-datepicker-in-asp-net-website -ローカリゼーション-part-3.aspx
また、カルチャをen-GBに設定しようとしたようですが、Web.ConfigでもUIカルチャを設定しようとしたかどうかはわかりません(これがMVCのjQueryバンドルに影響するかどうかはわかりません)。 )::
<globalization requestEncoding="utf-8" responseEncoding="utf-8" culture="en-GB" uiCulture="en-GB"/>
...またはそれが機能しない場合は(heh)、値を文字列として渡してから、APIコントローラーで解析してみませんか?
using System.Globalization;
// fetch the en-GB culture
CultureInfo ukCulture = new CultureInfo("en-GB");
// pass the DateTimeFormat information to DateTime.Parse
DateTime myDateTime = DateTime.Parse("StringValue" ,ukCulture.DateTimeFormat);