wake-up-neo.net

Ändern Sie das Standardformat für die DateTime-Analyse in ASP.NET Core

Ich erhalte ein Datum in einem ASP.NET Core Controller wie folgt:

public class MyController:Controller{
    public IActionResult Test(DateTime date) {

    }
}

Das Framework kann das Datum analysieren, jedoch nur im englischen Format. Wenn ich 04.12.2017 als Datumsparameter übergebe, meine ich den 4. Dezember 2017. Dies würde als englisches Datum analysiert, sodass mein Datumsobjekt den Wert 12. April 2017 erhält. Ich habe versucht, Deutsch nur mit hinzuzufügen das Artikel und auch das , aber ohne Erfolg.

Was muss getan werden, damit ASP.NET Core Daten automatisch im richtigen deutschen Format analysiert?

Update Ich habe versucht, die RequestLocalizationOptions festzulegen

services.Configure<RequestLocalizationOptions>(opts =>
{
    var supportedCultures = new[]
    {
        new CultureInfo("de-DE"),
    };

    opts.DefaultRequestCulture = new RequestCulture("de-DE");
    // Formatting numbers, dates, etc.
    opts.SupportedCultures = supportedCultures;
    // UI strings that we have localized.
    opts.SupportedUICultures = supportedCultures;
});

Funktioniert immer noch nicht. Ich rufe example.com/Test?date=12.04.2017 an und habe dies in meinem Debugger erhalten:

public IActionResult Test(DateTime date) {
    string dateString = date.ToString("d"); // 04.12.2016
    string currentDateString = DateTime.Now.ToString("d"); // 14.01.2016
    return Ok();
}
9
Lion

Hatte das gleiche Problem. Während das Übergeben von DateTime im Anforderungshauptteil einwandfrei funktioniert (da der Json-Konverter dieses Notensystem verarbeitet), hat das Übergeben von DateTime in der Abfragezeichenfolge als Parameter einige Kulturprobleme.

Ich mochte den Ansatz "Alle Anforderungskultur ändern" nicht, weil dies Auswirkungen auf die Analyse anderer Typen haben könnte, was nicht wünschenswert ist.

Daher entschied ich mich dafür, die standardmäßige DateTime-Modellbindung mit IModelBinder zu überschreiben: https://docs.Microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding

Was ich getan habe:

1) Definieren Sie einen benutzerdefinierten Ordner (c # 7-Syntax für 'out' -Parameter wird verwendet):

public class DateTimeModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
            throw new ArgumentNullException(nameof(bindingContext));

        // Try to fetch the value of the argument by name
        var modelName = bindingContext.ModelName;
        var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
        if (valueProviderResult == ValueProviderResult.None)
            return Task.CompletedTask;

        bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);

        var dateStr = valueProviderResult.FirstValue;
        // Here you define your custom parsing logic, i.e. using "de-DE" culture
        if (!DateTime.TryParse(dateStr, new CultureInfo("de-DE"), DateTimeStyles.None, out DateTime date))
        {
            bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, "DateTime should be in format 'dd.MM.yyyy HH:mm:ss'");
            return Task.CompletedTask;
        }

        bindingContext.Result = ModelBindingResult.Success(date);
        return Task.CompletedTask;
    }
}

2) Definieren Sie den Anbieter für Ihre Mappe:

 public class DateTimeModelBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (context.Metadata.ModelType == typeof(DateTime) || 
            context.Metadata.ModelType == typeof(DateTime?))
        {
            return new DateTimeModelBinder();
        }

        return null;
    }
}

3) Registrieren Sie schließlich Ihren Anbieter, um von ASP.NET Core verwendet zu werden:

services.AddMvc(options =>
{
    options.ModelBinderProviders.Insert(0, new DateTimeModelBinderProvider());
});

Jetzt wird Ihre DateTime wie erwartet analysiert.

9
Igor Fedchenko

Ich wollte die Datumsangaben in meinen Antworten formatieren und habe in der ConfigureServices-Methode Folgendes ausgeführt:

services.AddMvc()
.AddJsonOptions(options =>
{
    options.SerializerSettings.DateFormatString = "mm/dd/yy, dddd";
});

Hoffentlich hilft das.

6
PayamGerami

MVC hat immer InvariantCulture für Routendaten und Abfragezeichenfolgen (Parameter, die in die URL gehen) verwendet. Der Grund dafür ist, dass URLs in lokalisierten Anwendungen universell sein müssen. Ansonsten kann eine URL je nach Benutzergebiet unterschiedliche Daten bereitstellen.

Sie können die Abfrage und Route ValueProviderFactories durch Ihre eigene ersetzen, die die aktuelle Kultur berücksichtigt (oder method="POST" in Formularen verwenden). 

public class CustomValueProviderFactory : IValueProviderFactory
{
    public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        var query = context.ActionContext.HttpContext.Request.Query;
        if (query != null && query.Count > 0)
        {
            var valueProvider = new QueryStringValueProvider(
                BindingSource.Query,
                query,
                CultureInfo.CurrentCulture);

            context.ValueProviders.Add(valueProvider);
        }

        return Task.CompletedTask;
    }
}

services.AddMvc(opts => {
    // 2 - Index QueryStringValueProviderFactory
    opts.ValueProviderFactories[2] = new CustomValueProviderFactory(); 
})

P.S. Es ist vernünftiges Verhalten, aber ich verstehe nicht, warum die Dokumentation diese sehr wichtige Sache nicht behandelt.

2
justserega

Erwägen Sie die Verwendung einer benutzerdefinierten TypeConverter für Ihre datetime ( Source ):

using System;
using System.ComponentModel;
using System.Globalization;
using System.Drawing;

public class DeDateTimeConverter : TypeConverter {
   // Overrides the CanConvertFrom method of TypeConverter.
   // The ITypeDescriptorContext interface provides the context for the
   // conversion. Typically, this interface is used at design time to 
   // provide information about the design-time container.
   public override bool CanConvertFrom(ITypeDescriptorContext context, 
      Type sourceType) {

      if (sourceType == typeof(string)) {
         return true;
      }
      return base.CanConvertFrom(context, sourceType);
   }
   // Overrides the ConvertFrom method of TypeConverter.
   public override object ConvertFrom(ITypeDescriptorContext context, 
      CultureInfo culture, object value) {
      if (value is string) {
         if (DateTime.TryParse(((string)value), new CultureInfo("de-DE") /*or use culture*/, DateTimeStyles.None, out DateTime date))
             return date;
      }
      return base.ConvertFrom(context, culture, value);
   }
}

und verwenden Sie das TypeConverter-Attribut für Ihre Immobilie:

[TypeConverter(typeof(DeDateTimeConverter))]
public DateTime CustomDateTime { get; set; }

Update

Aufgrund meiner Erfahrung und dank dieser Antwort und @ zdeněk-Kommentar funktioniert das TypeConverter-Attribut nicht und Sie sollten TypeConverter in Startup.cs registrieren:

TypeDescriptor.AddAttributes(typeof(DateTime), new TypeConverterAttribute(typeof(DeDateTimeConverter)));
0
KiNG

Wenn es Ihnen nichts ausmacht, die generische StatusCode-Methode für diesen Aufruf zu verwenden, können Sie Folgendes tun:

internal IActionResult CreateResponse(int code, object content = null)
    {
        Type t = content?.GetType();
        bool textContent = t == typeof(string) || t == typeof(bool);
        //
        JsonSerializerSettings dateFormatSettings = new JsonSerializerSettings
        {

            DateFormatString = myDateFormat
        };

        string bodyContent = content == null || string.IsNullOrWhiteSpace(content + "")
                    ? null
                    : textContent
                        ? content + ""
                        : JsonConvert.SerializeObject(content, dateFormatSettings);

        ObjectResult or = base.StatusCode(code, bodyContent);
        string mediaType = 
                    !textContent
                        ? "application/json"
                        : "text/plain";
        or.ContentTypes.Add(new MediaTypeHeaderValue(mediaType));
        return or;
    }

Sie können dies zu einer Basisklasse hinzufügen und wie folgt aufrufen:

return base.CreateResponse(StatusCodes.Status200OK, new { name = "My Name", age = 23});

Es liegt an Ihnen, ob Sie Ihre eigenen Ok, BadRequest-Methoden usw. erstellen möchten, aber für mich funktioniert das und ich hoffe, es hilft allen anderen. Sie können sogar den Int-Code = 200 verwenden, wenn die meisten Ihrer Anforderungen GETs sind. Bei diesem Code wird davon ausgegangen, dass Sie entweder mit einer Zeichenfolge, einem booleschen Objekt oder einem benutzerdefinierten Objekt antworten möchten. Sie können jedoch alle Grundelemente problemlos behandeln, indem Sie Type.GetTypeInfo () überprüfen oder Guid.

0
pqsk

Ich hatte das gleiche Problem und wurde fast sauer. Ich habe alles ohne Erfolg versucht. Zuerst fand ich eine Problemumgehung, um einen Teil meines Problems zu lösen:

Abhilfe:

string data1 
string horainicio 
string horafim

var ageData = new AgendaData();
var user = await _userManager.GetUserAsync(User);
string usuario = user.Id;
int empresa = user.IdEmpresa;
int Idprospect = Convert.ToInt32(prospect);
int minutos = 0;           
var tipoAgenda = TipoAgenda.Contato;

var provider = CultureInfo.InvariantCulture;
provider = new CultureInfo("en-US");            
string formato = "dd/MM/yyyy HH:mm";

var dataInicio = DateTime.ParseExact(data1 + " " + horainicio, formato, provider);
var dataFim = DateTime.ParseExact(data1 + " " + horafim, formato, provider);           
var dataAlerta = dataInicio.AddMinutes(-minutos);

Aber auf diese Weise muss ich immer die Invariantkultur auf meine gesamte Datumszeit setzen. Ich habe die Lösung gefunden, die meine Kultur bei configure auf startup.cs einstellt.

Setze Kultur auf startup.cs

 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, CRMContext context)
        {
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
                app.UseBrowserLink();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            //Fixar Cultura para en-US
            RequestLocalizationOptions localizationOptions = new RequestLocalizationOptions
            {
                SupportedCultures = new List<CultureInfo> { new CultureInfo("en-US") },
                SupportedUICultures = new List<CultureInfo> { new CultureInfo("en-US") },
                DefaultRequestCulture = new RequestCulture("en-US")
            };

            app.UseRequestLocalization(localizationOptions);      
            app.UseStaticFiles();
            app.UseIdentity();

            // Add external authentication middleware below. To configure them please see https://go.Microsoft.com/fwlink/?LinkID=532715

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });

            context.Database.EnsureCreated();
        }

Hoffe das hilft dir.

0
Rogerio Azevedo

Versuchen Sie, die Kultur manuell in Ihrem web.config

<configuration>
   <system.web>    
      <globalization culture="de-DE" uiCulture="de-DE"/>
   </system.web>
</configuration>

BEARBEITEN: Da ich gerade gemerkt habe, dass dies Core ist, können Sie dies in StartUp.Configure folgendermaßen tun:

var cultureInfo = new CultureInfo("de-DE");
CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;
0
maksymiuk
              using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Threading.Tasks;
        using Microsoft.AspNetCore.Builder;
        using Microsoft.AspNetCore.Hosting;
        using Microsoft.Extensions.Configuration;
        using Microsoft.Extensions.DependencyInjection;
        using Microsoft.Extensions.Logging;
        using Microsoft.Extensions.Options;
        using System.Globalization;
        using Microsoft.AspNetCore.Localization;

        namespace coreweb
        {
            public class Startup
            {
                public Startup(IHostingEnvironment env)
                {
                    var builder = new ConfigurationBuilder()
                        .SetBasePath(env.ContentRootPath)
                        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                        .AddEnvironmentVariables();

                    if (env.IsDevelopment())
                    {
                        // This will Push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
                        builder.AddApplicationInsightsSettings(developerMode: true);
                    }
                    Configuration = builder.Build();
                }

                public IConfigurationRoot Configuration { get; }

                // This method gets called by the runtime. Use this method to add services to the container.
                public void ConfigureServices(IServiceCollection services)
                {
                    // ... previous configuration not shown
                    services.AddMvc();
                    services.Configure<RequestLocalizationOptions>(
                        opts =>
                        {
                            var supportedCultures = new[]
                            {

                        new CultureInfo("de-DE"),
                            };

                            opts.DefaultRequestCulture = new RequestCulture("de-DE");
                    // Formatting numbers, dates, etc.
                    opts.SupportedCultures = supportedCultures;
                    // UI strings that we have localized.
                    opts.SupportedUICultures = supportedCultures;
                        });
                }

                // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
                public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
                {
                    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
                    loggerFactory.AddDebug();

                 //   app.UseApplicationInsightsRequestTelemetry();

                    if (env.IsDevelopment())
                    {
                        app.UseDeveloperExceptionPage();
                        app.UseBrowserLink();
                    }
                    else
                    {
                        app.UseExceptionHandler("/Home/Error");
                    }

                  //  app.UseApplicationInsightsExceptionTelemetry();

                    app.UseStaticFiles();

                    var options = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
                    app.UseRequestLocalization(options.Value);



                    app.UseMvc(routes =>
                    {
                        routes.MapRoute(
                            name: "default",
                            template: "{controller=Home}/{action=Index}/{id?}");
                    });
                }
            }
        }
0
Yashveer Singh