【问题标题】:Azure Mobile App customizing json serializationAzure 移动应用自定义 json 序列化
【发布时间】:2016-04-29 15:08:52
【问题描述】:

我似乎无法在 Azure 移动应用中自定义 JSON 序列化。

为了避免我自己的代码过于复杂,我从头开始设置一个新项目。 Visual Studio Community 2015 Update 2,Azure App Service Tools v2.9(如果重要的话)。新项目、Visual C#、云、Azure 移动应用。

App_Start\Startup.MobileApp.cs 中,这是模板中的内容:

public static void ConfigureMobileApp(IAppBuilder app)
{
    HttpConfiguration config = new HttpConfiguration();

    new MobileAppConfiguration()
        .UseDefaultConfiguration()
        .ApplyTo(config);

    // Use Entity Framework Code First to create database tables based on your DbContext
    Database.SetInitializer(new MobileServiceInitializer());

    MobileAppSettingsDictionary settings = config.GetMobileAppSettingsProvider().GetMobileAppSettings();

    if (string.IsNullOrEmpty(settings.HostName))
    {
        app.UseAppServiceAuthentication(new AppServiceAuthenticationOptions
        {
            // This middleware is intended to be used locally for debugging. By default, HostName will
            // only have a value when running in an App Service application.
            SigningKey = ConfigurationManager.AppSettings["SigningKey"],
            ValidAudiences = new[] { ConfigurationManager.AppSettings["ValidAudience"] },
            ValidIssuers = new[] { ConfigurationManager.AppSettings["ValidIssuer"] },
            TokenHandler = config.GetAppServiceTokenHandler()
        });
    }

    app.UseWebApi(config);
}

这是我尝试过的:

public static void ConfigureMobileApp(IAppBuilder app)
{
    JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
    {
        Converters = { new StringEnumConverter { CamelCaseText = true }, },
        ContractResolver = new CamelCasePropertyNamesContractResolver { IgnoreSerializableAttribute = true },
        DefaultValueHandling = DefaultValueHandling.Ignore,
        NullValueHandling = NullValueHandling.Ignore,
        Formatting = Formatting.Indented
    };

    HttpConfiguration config = new HttpConfiguration();
    config.Formatters.JsonFormatter.SerializerSettings = JsonConvert.DefaultSettings();

    new MobileAppConfiguration()
        .UseDefaultConfiguration()
        .ApplyTo(config);

    ...
}

运行这个并访问http://localhost:53370/tables/TodoItem,json没有缩进,并且有一堆false字段,这表明设置被忽略了。

那么如何更改序列化程序设置,以便在此配置中尊重它们?从每个控制器返回一个带有我自己的自定义设置的JsonResult 是可行的,但只允许我发送200 OK 状态(我必须跳过箍返回一个尊重我的设置的201 Created)。

【问题讨论】:

  • 您解决了这个问题吗?我似乎遇到了类似的问题,即移动应用程序不尊重我的序列化程序设置。在我的情况下,引用循环处理不起作用导致 500 个响应。

标签: c# azure json.net


【解决方案1】:

Azure 移动应用目前似乎不遵守在 OWIN 启动类中设置的序列化程序设置。我不知道它们是否被覆盖或只是没有被使用,但它们没有被控制器拾取。

作为一种解决方法,您似乎可以从控制器内部设置序列化程序设置:

public class SomeController : ApiController
{
    public object Get()
    {
          SetSerializerSettings();
          Do your logic....
    }

    private void SetSerializerSettings()
    {
          this.Configuration.Formatters.JsonFormatter.SerializerSettings = 
              new JsonSerializerSettings
              {
                 Converters = { new StringEnumConverter { CamelCaseText = true }, },
                 ContractResolver = 
                       new CamelCasePropertyNamesContractResolver { IgnoreSerializableAttribute = true },
                 DefaultValueHandling = DefaultValueHandling.Ignore,
                 NullValueHandling = NullValueHandling.Ignore,
                 Formatting = Formatting.Indented
              };
    }

}

Configuration 属性尚未在构造函数中设置,因此您不能将SetSerializerSettings() 放在那里,因为它会被覆盖。只要进程正在运行,这些设置似乎就会持续存在,所以这有点多余,但它似乎确实完成了工作。我希望有人能过来并提供正确的方法!

【讨论】:

  • 在我的例子中,我做了一个覆盖 Initialize 的基本控制器;在那里您可以访问所有设置。
【解决方案2】:

在这上面花了很多时间之后,我认为你能做的最好的事情就是创建一个MobileAppControllerConfigProvider 并将其传递给WithMobileAppControllerConfigProvider

这就是我正在做的,让所有控制器尊重JsonConvert.DefaultSettings

JsonConvert.DefaultSettings = () => new JsonSerializerSettings { /* something */ };

var provider = new MobileConfigProvider();

var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.Formatters.JsonFormatter.UseDataContractJsonSerializer = false;
config.Formatters.JsonFormatter.SerializerSettings = provider.Settings;

new MobileAppConfiguration().
    MapApiControllers().
    AddMobileAppHomeController().
    AddPushNotifications().
    WithMobileAppControllerConfigProvider(provider).
    ApplyTo(config);

还有:

sealed class MobileConfigProvider : MobileAppControllerConfigProvider
{
    readonly Lazy<JsonSerializerSettings> settings = new Lazy<JsonSerializerSettings>(JsonConvert.DefaultSettings);

    public JsonSerializerSettings Settings => settings.Value;

    public override void Configure(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
    {
        base.Configure(controllerSettings, controllerDescriptor);
        controllerSettings.Formatters.JsonFormatter.SerializerSettings = Settings;
    }
}

【讨论】:

  • 谢谢!这比我的解决方法要好得多!
【解决方案3】:

作为 DevNoob 的回答,OWIN 启动类中的序列化程序设置不起作用。当设置在每个控制器类的 Initialize(HttpControllerContext controllerContext) 方法中时,它可以工作。就我而言,我有自引用问题,所以我解决了这样的问题:

public class CustomerController : TableController<Customer>
{
    protected override void Initialize(HttpControllerContext controllerContext)
    {

        controllerContext.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

        base.Initialize(controllerContext);
        MyMobileAppContext context = new MyMobileAppContext();
        DomainManager = new EntityDomainManager<Customer>(context, Request);
    }

....

}

【讨论】:

    【解决方案4】:

    我建议小心此处提供的答案。一切都很好,直到我们在 iOS 应用程序中使用离线同步表。

    在我的情况下,它们没有任何充分的理由就崩溃了,很可能它们需要一些非默认的序列化程序设置才能正常运行。我使用了 Nuno Cruses 的解决方案,当我恢复时一切恢复正常。

    【讨论】:

      猜你喜欢
      • 2011-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-02
      相关资源
      最近更新 更多