9

I know this is duplicate of some past questions.But there were no real solution.

One of the related links

Another one

I am working with .Net Core 3 Multipage Template. I've tried everything like given below. But no use.

This is my interface from application project:

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using TSE.Kalibrasyon.Roles.Dto;
using TSE.Kalibrasyon.Users.Dto;

namespace TSE.Kalibrasyon.Labs
{
    public interface ILabAppService : IApplicationService
    {
        string Test();
        Task<List<Entities.Labs.Labs>> GetAllAsync();
        System.Threading.Tasks.Task Update(Entities.Labs.Labs input);
        System.Threading.Tasks.Task Create(Entities.Labs.Labs input);
    }
}

and the implementation is:

using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Entities;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.IdentityFramework;
using Abp.Linq.Extensions;
using Abp.Localization;
using Abp.Runtime.Session;
using Abp.UI;
using TSE.Kalibrasyon.Authorization;
using TSE.Kalibrasyon.Authorization.Accounts;
using TSE.Kalibrasyon.Authorization.Roles;
using TSE.Kalibrasyon.Authorization.Users;
using TSE.Kalibrasyon.Roles.Dto;
using TSE.Kalibrasyon.Users.Dto;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using TSE.Kalibrasyon.Entities.Labs.Dto;
using TSE.Kalibrasyon.Entities.Labs;
using TSE.Kalibrasyon.Labs.Dto;
using Abp.Web.Models;
using Newtonsoft.Json;
using Microsoft.AspNetCore.Mvc;

namespace TSE.Kalibrasyon.Labs
{
    //[AbpAuthorize(PermissionNames.Pages_Users)]
    public class LabAppService : KalibrasyonAppServiceBase, ILabAppService
    {
        private readonly IRepository<Entities.Labs.Labs> _labRepository;


        public LabAppService(IRepository<Entities.Labs.Labs> labRepository)
        {
            _labRepository = labRepository;
        }
        [Microsoft.AspNetCore.Mvc.HttpGet]
        public string Test()
        {
            return "merhaba";
        }
        [DontWrapResult]
        public  async Task<List<Entities.Labs.Labs>> GetAllAsync()
        {
            //var chk = await _labRepository.GetAllListAsync();
            return await _labRepository.GetAllListAsync();
        }

        [DontWrapResult]
        //public  List<Entities.Labs.Labs> GetAll2()
        public  object GetAll2()
        {
            List<Entities.Labs.Labs> chk = _labRepository.GetAllListAsync().Result;
            //return _labRepository.GetAllListAsync().Result;
            var bak= new { Items = chk, Count = chk.Count() };
            return new { Items = chk, Count = chk.Count() };
            //return Json(new { Items = chk, Count = chk.Count() }, new JsonSerializerSettings { ContractResolver = new PascalCasePropertyNamesContractResolver() });
        }

        [DontWrapResult]
        public string GetAll3()
        {
            List<Entities.Labs.Labs> chk = _labRepository.GetAllListAsync().Result;
            var obj= new { Items = chk, Count = chk.Count() };
            //return Json(new { Items = chk, Count = chk.Count() }, new JsonSerializerSettings { ContractResolver = new PascalCasePropertyNamesContractResolver() });
            var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
            //var text = JsonConvert.SerializeObject(configuration, settings);
            var text = JsonConvert.SerializeObject(obj);
            return text;
            //return Json(new { Items = chk, Count = chk.Count() });

        }

        public async Task Update(Entities.Labs.Labs input)
        {
            await _labRepository.UpdateAsync(input);
        }
        public async Task Create(Entities.Labs.Labs input)
        {
            await _labRepository.InsertAsync(input);
        }
    }


    //public class Data
    //{
    //    public bool requiresCounts { get; set; }
    //    public int skip { get; set; }
    //    public int take { get; set; }
    //}
}

and the response body is:

[
  {
    "labName": "BASINÇ KALİBRASYON LABORATUVARI",
    "labKod": "BAS",
    "bolgeKodu": 5,
    "id": 1
  }
]

My model for this entity is :

using Abp.Domain.Entities;
using Abp.Domain.Repositories;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;

namespace TSE.Kalibrasyon.Entities.Labs
{
    [Table("Labs")]
    public partial class Labs : Entity
    {
        private readonly IRepository<Labs> _lablarRepository;
        //private readonly TownAppService _townAppService;
        //private readonly IRepository<Town> _townRepository;
        public Labs()
        {
            //this.Towns = new List<Town>();
            //this.Districts = new List<District>();
            //this.Neighborhoods = new List<Neighborhood>();
            OnCreated();
        }

        //[System.ComponentModel.DataAnnotations.Key]
        //[System.ComponentModel.DataAnnotations.Required()]
        //public virtual int Id
        //{
        //    get;
        //    set;
        //}

        [System.ComponentModel.DataAnnotations.Required()]
        public virtual string LabName
        {
            get;
            set;
        }

        [System.ComponentModel.DataAnnotations.StringLength(3)]
        [System.ComponentModel.DataAnnotations.Required()]
        public virtual string LabKod
        {
            get;
            set;
        }

        [System.ComponentModel.DataAnnotations.Required()]
        public virtual int BolgeKodu
        {
            get;
            set;
        }





        #region Extensibility Method Definitions

        partial void OnCreated();

        #endregion
    }
}

And there is an another big problem also, I am using Syncfusion .Net Core Grid as a third party tool. It requires a method for database operations as given below.

[IgnoreAntiforgeryToken]
        public IActionResult UrlDatasource([FromBody]DataManagerRequest dm)
        {
            Api api=new Api();

            //IEnumerable DataSource = Orders.GetAllRecords();
            IEnumerable DataSource = api.LabsGetAll();
            DataOperations operation = new DataOperations();


            if (dm.Search != null && dm.Search.Count > 0)
            {
                DataSource = operation.PerformSearching(DataSource, dm.Search);  //Search
            }
            if (dm.Sorted != null && dm.Sorted.Count > 0) //Sorting
            {
                DataSource = operation.PerformSorting(DataSource, dm.Sorted);
            }
            if (dm.Where != null && dm.Where.Count > 0) //Filtering
            {
                DataSource = operation.PerformFiltering(DataSource, dm.Where, dm.Where[0].Operator);



            }
            int count = DataSource.Cast<Entities.Labs.Labs>().Count();
            if (dm.Skip != 0)
            {
                DataSource = operation.PerformSkip(DataSource, dm.Skip);         //Paging
            }
            if (dm.Take != 0)
            {
                DataSource = operation.PerformTake(DataSource, dm.Take);
            }
            return dm.RequiresCounts ? Json(new { result = DataSource, count = count }) : Json(DataSource);
        }

When I don't use the [IgnoreAntiforgeryToken] for the method. It doesn't hit the method with the HTTP ERROR 415.

Syncfusion says that, it is just because of camel casing and offers adding the

services.PostConfigure<MvcJsonOptions>(options =>
{
    options.SerializerSettings.ContractResolver = new DefaultContractResolver();
}); 

into ConfigureServices method of StartUp file. But I think it works only with the .net core 2.x. It was not a solution for me with ABP working on .net core 3.0

My StartUp.cs in Host App is:

using System;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Castle.Facilities.Logging;
using Abp.AspNetCore;
using Abp.AspNetCore.Mvc.Antiforgery;
using Abp.Castle.Logging.Log4Net;
using Abp.Extensions;
using TSE.Kalibrasyon.Configuration;
using TSE.Kalibrasyon.Identity;
using Abp.AspNetCore.SignalR.Hubs;
using Abp.Dependency;
using Abp.Json;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json.Serialization;
using Microsoft.AspNetCore.Mvc;

namespace TSE.Kalibrasyon.Web.Host.Startup
{
    public class Startup
    {
        private const string _defaultCorsPolicyName = "localhost";

        private readonly IConfigurationRoot _appConfiguration;

        public Startup(IWebHostEnvironment env)
        {
            _appConfiguration = env.GetAppConfiguration();
        }

        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            //MVC
            services.AddControllersWithViews(
                options =>
                {
                    options.Filters.Add(new AbpAutoValidateAntiforgeryTokenAttribute());
                }
            ).AddNewtonsoftJson(options =>
            {
                //options.SerializerSettings.ContractResolver = new AbpMvcContractResolver(IocManager.Instance)
                //{
                //    NamingStrategy = new CamelCaseNamingStrategy()
                //};
                options.SerializerSettings.ContractResolver = new DefaultContractResolver();
            });


            services.PostConfigure<MvcNewtonsoftJsonOptions>(options =>
            {
                options.SerializerSettings.ContractResolver = new DefaultContractResolver();
            });



            IdentityRegistrar.Register(services);
            AuthConfigurer.Configure(services, _appConfiguration);

            services.AddSignalR();

            // Configure CORS for angular2 UI
            services.AddCors(
                options => options.AddPolicy(
                    _defaultCorsPolicyName,
                    builder => builder
                        .WithOrigins(
                            // App:CorsOrigins in appsettings.json can contain more than one address separated by comma.
                            _appConfiguration["App:CorsOrigins"]
                                .Split(",", StringSplitOptions.RemoveEmptyEntries)
                                .Select(o => o.RemovePostFix("/"))
                                .ToArray()
                        )
                        .AllowAnyHeader()
                        .AllowAnyMethod()
                        .AllowCredentials()
                )
            );

            // Swagger - Enable this line and the related lines in Configure method to enable swagger UI
            services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo() { Title = "Kalibrasyon API", Version = "v1" });
                options.DocInclusionPredicate((docName, description) => true);

                // Define the BearerAuth scheme that's in use
                options.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme()
                {
                    Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.ApiKey
                });
            });

            // Configure Abp and Dependency Injection
            return services.AddAbp<KalibrasyonWebHostModule>(
                // Configure Log4Net logging
                options => options.IocManager.IocContainer.AddFacility<LoggingFacility>(
                    f => f.UseAbpLog4Net().WithConfig("log4net.config")
                )
            );
        }

        public void Configure(IApplicationBuilder app,  ILoggerFactory loggerFactory)
        {
            app.UseAbp(options => { options.UseAbpRequestLocalization = false; }); // Initializes ABP framework.

            app.UseCors(_defaultCorsPolicyName); // Enable CORS!

            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthentication();

            app.UseAbpRequestLocalization();


            app.UseEndpoints(endpoints =>
            {
                endpoints.MapHub<AbpCommonHub>("/signalr");
                endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
                endpoints.MapControllerRoute("defaultWithArea", "{area}/{controller=Home}/{action=Index}/{id?}");
            });

            // Enable middleware to serve generated Swagger as a JSON endpoint
            app.UseSwagger();
            // Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)
            app.UseSwaggerUI(options =>
            {
                options.SwaggerEndpoint(_appConfiguration["App:ServerRootAddress"].EnsureEndsWith('/') + "swagger/v1/swagger.json", "Kalibrasyon API V1");
                options.IndexStream = () => Assembly.GetExecutingAssembly()
                    .GetManifestResourceStream("TSE.Kalibrasyon.Web.Host.wwwroot.swagger.ui.index.html");
            }); // URL: /swagger
        }
    }
}

Is there any solution that you might know? Thanks in advance.

and also, Controlling serialization of property names with JsonResult. But no use.Any idea please?

7
  • Please read How to Ask and show us how you determine "no result". Show how you generate the response and how you obtain the output. Commented Jan 2, 2020 at 7:11
  • @CodeCaster Ok. I've updated my question. It is always a tedious task asking here. There is a problem of mine. And there are always members of doctoral jury. It was just a question that was telling what was intented with my limited english. That is all .. Commented Jan 2, 2020 at 7:23
  • "It is always a tedious task asking here" - just remember that we can't look on your screen nor into your head. You have to explain all the relevant parts. Your question still doesn't show your code or your output. Commented Jan 2, 2020 at 7:33
  • @CodeCaster I've started to feel that, you realy want to help me with that problem. Thank you for your interest. I've updated my question once again. Thanks in advance Commented Jan 2, 2020 at 8:02
  • 1
    Of course there's a way, but you've shown way too much code. See for example stackoverflow.com/a/58135043/266143. Commented Jan 2, 2020 at 14:40

6 Answers 6

8

In .NET Core 3.x, you now need to modify JsonSerializerOptions.PropertyNamingPolicy.

For PascalCase — following your original property name — set to null:

services.AddMvc(...)
    .AddJsonOptions(jsonOptions =>
    {
        jsonOptions.JsonSerializerOptions.PropertyNamingPolicy = null;
    });

For lowercase (or another custom naming policy), subclass JsonNamingPolicy and override the ConvertName method.

services.AddMvc(...)
    .AddJsonOptions(jsonOptions =>
    {
        jsonOptions.JsonSerializerOptions.PropertyNamingPolicy = new JsonLowercaseNamingPolicy();
    });
public class JsonLowercaseNamingPolicy : JsonNamingPolicy
{
    public override string ConvertName(string name) => name.ToLowerInvariant();
}

Reference: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-how-to?view=netcore-3.1#use-a-custom-json-property-naming-policy

Sign up to request clarification or add additional context in comments.

2 Comments

This is assuming that the user is using the new .net json serializer. I'm having a hard time coming up with a way to do this in Newtonsoft.
@RobertSmith on .net6.0, in Startup.cs I had to add this services.AddControllers().AddNewtonsoftJson(options => { options.SerializerSettings.ContractResolver = new DefaultContractResolver(); }) for PascalCase
8

In .NET 6.0, I managed to fix the same issue, just add this code inside Program.cs (ofc, with Newtonsoft package previously installed.):

builder.Services.AddControllers().AddJsonOptions(options => 
options.JsonSerializerOptions.PropertyNamingPolicy = null);

1 Comment

surely AddJsonOptions is Json.Net, not NewtonsoftJson?
5

In .Net 8 there is an extra option needed. I also made this into an attribute to make it reusable.

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Formatters;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;

public class PreserveJsonCaseAttribute : ActionFilterAttribute
{
    private static readonly SystemTextJsonOutputFormatter Formatter = new SystemTextJsonOutputFormatter(
    new JsonSerializerOptions
    {
        PropertyNamingPolicy = null,
        TypeInfoResolver = new DefaultJsonTypeInfoResolver() // New line that is needed compared to previous answers
    }
);

public override void OnActionExecuted(ActionExecutedContext context)
{
    if (context.Result is ObjectResult objectResult)
        objectResult.Formatters.Add(Formatter);
}

And then you can decorate your controller method with

[PreserveJsonCase]

3 Comments

needs namespace System.Text.Json.Serialization.Metadata
I updated my answer to include all the using statements it needs
OMG thankyou, was tearing my hair out wondering why my code had started erroring!
4

For newtonsoft this is the implementation.

.AddControllersWithViews()
.AddNewtonsoftJson(options =>
{
    options.SerializerSettings.ContractResolver = null;
}
);

Hope it helps.

Comments

0

For other readers, trying to figure out how to do this in ASP.NET Core 7.0. It seems, the JSON serialization for API responses using the new Result methods (e.g. Results.Ok(obj)) does not respect the global serializer options set using AddControllers.

Instead, you can pass jsonOptions to Result.Json like this:

app.MapGet("/", () =>
{
    var jsonOptions = new JsonSerializerOptions
    {
        PropertyNamingPolicy = null
    };

    return Results.Json(
        new { Hello = "World" },
        jsonOptions,
        statusCode: (int?)HttpStatusCode.OK);
});

This could be extracted into a utility method

public static class ResultExtensions
{
    public static IResult OkPascalCase<T>(this T obj)
    {
        var options = new JsonSerializerOptions
        {
            PropertyNamingPolicy = null
        };
        return Results.Json(obj, options, statusCode: (int?)HttpStatusCode.OK);
    }
}
app.MapGet("/", () =>
{
    return ResultExtensions.OkPascalCase(new { Hello = "World" });
});

Comments

0

In .NET 8 if you want to preserve the naming case based on property name, add the line below to program.cs file.

builder.Services.AddControllers().AddJsonOptions(options =>
{
    options.JsonSerializerOptions.PropertyNamingPolicy = null;
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.