Change JSON serialization from camelCase to PascalCase [Duplicate-No solution?] - aspnetboilerplate

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?

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

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);

For newtonsoft this is the implementation.
.AddControllersWithViews()
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = null;
}
);
Hope it helps.

Related

Disable Wrapping of Controller Results

I am currently using v3.2.5 of Abp.AspNetCore.
I am trying to integrate an Alpha package of Microsoft.AspNetCore.OData into the project which is so far looking ok.
However when i try and query the metadata controller http://localhost:51078/odata/v1/$metadata the result is wrapped.
Now this was an issue for the ODataControllers as well, but i could simply add
the [DontWrapResult] attribute.
I dont have direct access to the MetadataController so i am unable to add the attribute. Is there anyway to disable wrapping for an Abp project?
Thanks
Edit
Here is the current ConfigureServices method
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services
.AddMvc()
.AddJsonOptions(options => { options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; });
services
.AddAuthentication()
.AddCsDeviceAuth(options => { });
services
.AddOData();
//Configure Abp and Dependency Injection
var provider = services.AddAbp<PortalWebODataModule>(options =>
{
//Configure Log4Net logging
options.IocManager.IocContainer.AddFacility<LoggingFacility>(
f => f.LogUsing<Log4NetLoggerFactory>().WithConfig("log4net.config")
);
});
services.Configure<MvcOptions>(options =>
{
var abpResultFilter = options.Filters.First(f => f is AbpResultFilter);
options.Filters.Remove(abpResultFilter);
options.Filters.AddService(typeof(ODataResultFilter));
});
return provider;
}
You can implement IResultFilter and set WrapOnSuccess to false:
public class ResultFilter : IResultFilter, ITransientDependency
{
private readonly IAbpAspNetCoreConfiguration _configuration;
public ResultFilter(IAbpAspNetCoreConfiguration configuration)
{
_configuration = configuration;
}
public void OnResultExecuting(ResultExecutingContext context)
{
if (context.HttpContext.Request.Path.Value.Contains("odata"))
{
var methodInfo = context.ActionDescriptor.GetMethodInfo();
var wrapResultAttribute =
GetSingleAttributeOfMemberOrDeclaringTypeOrDefault(
methodInfo,
_configuration.DefaultWrapResultAttribute
);
wrapResultAttribute.WrapOnSuccess = false;
}
}
public void OnResultExecuted(ResultExecutedContext context)
{
// No action
}
private TAttribute GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<TAttribute>(MemberInfo memberInfo, TAttribute defaultValue = default(TAttribute), bool inherit = true)
where TAttribute : class
{
return memberInfo.GetCustomAttributes(true).OfType<TAttribute>().FirstOrDefault()
?? memberInfo.DeclaringType?.GetTypeInfo().GetCustomAttributes(true).OfType<TAttribute>().FirstOrDefault()
?? defaultValue;
}
}
Then, in Startup class, add the filter in ConfigureServices method:
services.AddMvc(options =>
{
options.Filters.AddService(typeof(ResultFilter));
});
References:
AbpResultFilter.OnResultExecuting
ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault
Alternative solution; to completely disable WrapResult behavior within the system ( at the Core module registration):
var abpAspNetCoreConfiguration = Configuration.Modules.AbpAspNetCore();
abpAspNetCoreConfiguration.DefaultWrapResultAttribute.WrapOnSuccess = false;
abpAspNetCoreConfiguration.DefaultWrapResultAttribute.WrapOnError = false;
abpAspNetCoreConfiguration
.CreateControllersForAppServices(
typeof(AccessApplicationModule).GetAssembly()
);
WrapOnSuccess and WrapOnError flags can be set to false values.
ABP v6.5 and later
Implement IWrapResultFilter and add it to WrapResultFilters in the module's PreInitialize method.
See https://stackoverflow.com/questions/70947461/how-to-control-response-wrapping-in-abp-on-a-per-route-basis/70955045#70955045 for more details.
Before ABP v6.5
...including ABP v3.2.5 mentioned in the question.
Subclass AbpResultFilter:
using Abp.AspNetCore.Configuration;
using Abp.AspNetCore.Mvc.Results;
using Abp.AspNetCore.Mvc.Results.Wrapping;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
namespace AbpODataDemo.Web.Host.Filters
{
public class ODataResultFilter : AbpResultFilter
{
public ODataResultFilter(IAbpAspNetCoreConfiguration configuration, IAbpActionResultWrapperFactory actionResultWrapperFactory)
: base(configuration, actionResultWrapperFactory)
{
}
public override void OnResultExecuting(ResultExecutingContext context)
{
if (context.HttpContext.Request.Path.Value.StartsWith("/odata", StringComparison.InvariantCultureIgnoreCase))
{
return;
}
base.OnResultExecuting(context);
}
}
}
Replace AbpResultFilter with it in the Startup ConfigureServices method:
services.PostConfigure<MvcOptions>(options =>
{
var index = options.Filters.IndexOf(new ServiceFilterAttribute(typeof(AbpResultFilter)));
if (index != -1)
{
options.Filters.RemoveAt(index);
options.Filters.Insert(index, new ServiceFilterAttribute(typeof(ODataResultFilter)));
}
});
Reference: https://github.com/aspnetboilerplate/sample-odata/pull/16

Loading Image while service gets data using Xamarin Forms

In my application in login page i want loading image with message "Loading" in xamarin forms before the service gets data.
For that i used Activity indicator like this:
ActivityIndicator indicator = new ActivityIndicator { Color = Color.Blue, };
indicator.IsRunning = false;
indicator.IsVisible = false;
indicator.HorizontalOptions = LayoutOptions.CenterAndExpand;
indicator.VerticalOptions = LayoutOptions.CenterAndExpand;
and after click on Login button,I added code like this
indicator.IsRunning = true;
indicator.IsVisible = true;
now i am getting loading image only and in the same screen.But i want like the above image.can anyone suggest me to solve this.
Thanks in advance
You can use following library for the Dialogs
It supports Xamarin.Forms aswell
https://www.nuget.org/packages/Acr.UserDialogs/
EDIT 1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
**using Acr.UserDialogs;**
using Xamarin.Forms;
using Splat;
namespace ProjectScreen
{
public partial class MainPage : ContentPage
{
public ObservableCollection<MainPageViewModel> projects { get; set; }
public SQLite.Net.SQLiteConnection _connection;
public bool IsLoading;
public MainPage()
{
projects = new ObservableCollection<MainPageViewModel>();
InitializeComponent();
this.getConnection();
foreach (Project Pname in this.GetProjects())
{
projects.Add(new MainPageViewModel { Name = Pname.name });
lstView.ItemsSource = projects;
}
AddNewItem.Clicked += (o, s) =>
{
this.PromptCommand();
};
lstView.ItemSelected += LstView_ItemSelected;
}
private void LstView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
**UserDialogs.Instance.ShowLoading("Loading data");**
Task.Run(() => { waitForMinute(); });
}
private async void waitForMinute()
{
await Task.Delay(10000);
**UserDialogs.Instance.Loading().Hide();**
Device.BeginInvokeOnMainThread(() =>
{
Navigation.PushAsync(new NavigationPage(new ProjectDetails()));
});
}
}
}
}
Lines indicated with ** are for AcrDialog You can use them in any file as per your requirement
make Sure you run them on main thread

Telerik Data Access - Argument Null Exception (ConverterName)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VideoWebsite.DataAccess;
namespace VideoWebsite.Models
{
public class DatabaseModel
{
public int DatabaseID { get; set; }
public string DatabaseName { get; set; }
}
public class DatabaseModelAccess
{
public static IEnumerable<DatabaseModel> All()
{
string queryString = #"SELECT 1 as DatabaseID, 'test' as DatabaseName";
using (EntitiesModelA2 dbContext2 = new EntitiesModelA2())
{
IEnumerable<DatabaseModel> result = dbContext2.ExecuteQuery<DatabaseModel>(queryString); //Exception occurs here
return result;
}
}
}
}
I am trying to materialize the non persistent type.
I am using the postgres database to generate the EntitiesModelA2.
From Telerik Data Access perspective, the error appears because the query does not have a FROM clause (it does not comply to the basic syntax for SELECT statements).
You can execute it like this:
Option 1
using (EntitiesModelA2 dbContext = new EntitiesModelA2())
{
using (IDbConnection connect = dbContext.Connection)
{
using (IDbCommand command = connect.CreateCommand())
{
command.CommandText = "SELECT 1 as DatabaseID, 'test' as DatabaseName FROM ExistingTableName";
using (IDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
var result = new DatabaseModel();
result.DatabaseID = reader.GetInt32(0);
result.DatabaseName = reader.GetString(1);
//do something with the result
}
}
}
}
}
Option 2
using (EntitiesModelA2 dbContext = new EntitiesModelA2())
{
var result = dbContext.ExecuteQuery<DatabaseModel>("SELECT 1 as DatabaseID, 'test' as DatabaseName FROM ExistingTableName");
}

Integrating AspNet.WebApi with AspNet.SignalR

I want to integrate Microsoft.AspNet.SignalR version="2.1.2" with Microsoft.AspNet.WebApi version="5.2.2" so that the API can communicate in REAL-TIME. I found one VERY NICE SAMPLE that implements/works exactly the same way I want, but the sample uses jquery.signalR-0.5.0.js. Some of the earlier implementations have changed, and so far here is what I have done in a failed effort to upgrade the solution to use the latest signalr, asp.net web api and owin.
I left the Hub as it is
using SignalR.Hubs;
namespace NdcDemo.Hubs
{
// This hub has no inbound APIs, since all inbound communication is done
// via the HTTP API. It's here for clients which want to get continuous
// notification of changes to the ToDo database.
[HubName("todo")]
public class ToDoHub : Hub { }
}
I also left the ApiControllerWithHub class as it is
using System;
using System.Web.Http;
using SignalR;
using SignalR.Hubs;
namespace NdcDemo.Controllers
{
public abstract class ApiControllerWithHub<THub> : ApiController
where THub : IHub
{
Lazy<IHubContext> hub = new Lazy<IHubContext>(
() => GlobalHost.ConnectionManager.GetHubContext<THub>()
);
protected IHubContext Hub
{
get { return hub.Value; }
}
}
}
For the ToDoController, I changed the
Hub.Clients.addItem(item), Hub.Clients.updateItem(toUpdate),
Hub.Clients.deleteItem(id)
to
Hub.Clients.All.addItem(item), Hub.Clients.All.updateItem(toUpdate),
Hub.Clients.All.deleteItem(id)
and this is now the full ToDoController class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Web.Http;
using NdcDemo.Hubs;
using NdcDemo.Models;
namespace NdcDemo.Controllers
{
[InvalidModelStateFilter]
public class ToDoController : ApiControllerWithHub<ToDoHub>
{
private static List<ToDoItem> db = new List<ToDoItem>
{
new ToDoItem { ID = 0, Title = "Do a silly demo on-stage at NDC" },
new ToDoItem { ID = 1, Title = "Wash the car" },
new ToDoItem { ID = 2, Title = "Get a haircut", Finished = true }
};
private static int lastId = db.Max(tdi => tdi.ID);
public IEnumerable<ToDoItem> GetToDoItems()
{
lock (db)
return db.ToArray();
}
public ToDoItem GetToDoItem(int id)
{
lock (db)
{
var item = db.SingleOrDefault(i => i.ID == id);
if (item == null)
throw new HttpResponseException(
Request.CreateResponse(HttpStatusCode.NotFound)
);
return item;
}
}
public HttpResponseMessage PostNewToDoItem(ToDoItem item)
{
lock (db)
{
// Add item to the "database"
item.ID = Interlocked.Increment(ref lastId);
db.Add(item);
// Notify the connected clients
Hub.Clients.addItem(item);
// Return the new item, inside a 201 response
var response = Request.CreateResponse(HttpStatusCode.Created, item);
string link = Url.Link("apiRoute", new { controller = "todo", id = item.ID });
response.Headers.Location = new Uri(link);
return response;
}
}
public ToDoItem PutUpdatedToDoItem(int id, ToDoItem item)
{
lock (db)
{
// Find the existing item
var toUpdate = db.SingleOrDefault(i => i.ID == id);
if (toUpdate == null)
throw new HttpResponseException(
Request.CreateResponse(HttpStatusCode.NotFound)
);
// Update the editable fields and save back to the "database"
toUpdate.Title = item.Title;
toUpdate.Finished = item.Finished;
// Notify the connected clients
Hub.Clients.updateItem(toUpdate);
// Return the updated item
return toUpdate;
}
}
public HttpResponseMessage DeleteToDoItem(int id)
{
lock (db)
{
int removeCount = db.RemoveAll(i => i.ID == id);
if (removeCount <= 0)
return Request.CreateResponse(HttpStatusCode.NotFound);
// Notify the connected clients
Hub.Clients.deleteItem(id);
return Request.CreateResponse(HttpStatusCode.OK);
}
}
}
}
And then I put app.MapSignalR();
But the demo doesn't work...the API doesn't contact clients...Where am I going wrong?
I would still appreciate any more simpler recommendations based on this solution.
Solution from OP.
Answer:
After a a cup of camomile tea, i found out that the clients had to include the KEYWORD CLIENT before the dynamic methods in Todo.js... So, here is what that needs to be modified so that the sample works
hub.client.addItem = function (item) {
alert("i just received something...");
viewModel.add(item.ID, item.Title, item.Finished);
};
hub.client.deleteItem = function (id) {
viewModel.remove(id);
};
hub.client.updateItem = function (item) {
viewModel.update(item.ID, item.Title, item.Finished);
};
And it works!

LINQ to Entity: How to cast a complex type to a DTO

Background:
I have created a function import which is available in my context object as GetJournalViewItemsQuery()
The function import returns a complex type called JournalViewItem.
Now when I try to load the JournalViewItem into my application DTO called JournalEntry I come up with error:
Error 7 Cannot implicitly convert type 'MyApp.Infrastructure.Models.JournalEntry' to 'MyApp.SqlData.JournalViewItem'
This is the code:
var journalEntry = Context.GetJournalViewItemsQuery()
.Where(i => i.JournalItemId == _journalEntryId)
.Select(x => new JournalEntry(x.JournalItemId,
x.HeaderText,x.JournalText, x.LastUpdatedOn,
x.JournalItemTypeId)).Single();
The error happens at the "new JournalEntry" line.
My question: How can I cast the JournalViewItem complex type to my DTO ?
Thank you
After #JanR suggestion I still have the same problem. The modified code is:
var journalEntry = Context.GetJournalViewItemsQuery()
.Where(i => i.JournalItemId == _journalEntryId)
.Select(x => new JournalEntry
{
JournalEntryNumber = x.JournalItemId,
HeaderText = x.HeaderText,
BodyText = x.JournalText,
LastUpdatedOn = x.LastUpdatedOn,
JournalEntryType = x.JournalItemTypeId
}).Single();
I found out the reason for my problem. I failed to mention (my apologies) that I'm working off generated code from WCF RIA Domain Services for Silverlight application. As such the Context.GetJournalViewItemsQuery() needs to be executed and THEN I can query the results on my callback method using the LINQ expression that #Chuck.Net and JanR have suggested.
Here's the working code to those who might be interested:
public IList<JournalEntryHeader> GetJournalEntryHeaders()
{
PerformQuery<JournalViewItem>(Context.GetJournalViewItemsQuery(), GetJournalEntryHeadersFromDbComplete);
return _journalHeaders;
}
void PerformJournalEntryHeadersQuery(EntityQuery<JournalViewItem> qry,
EventHandler<EntityResultsArgs<JournalViewItem>> evt)
{
Context.Load<JournalViewItem>(qry, r =>
{
if (evt != null)
{
try
{
if (r.HasError)
{
evt(this, new EntityResultsArgs<JournalViewItem>(r.Error));
}
else if (r.Entities.Count() > 0)
{
evt(this, new EntityResultsArgs<JournalViewItem>(Context.JournalViewItems));
}
else if (r.Entities.Count() == 0 && _currentJournalItemsPage > 0)
{
GetPrevPageJournalEntryHeadersAsync();
}
}
catch (Exception ex)
{
evt(this, new EntityResultsArgs<JournalViewItem>(ex));
}
}
}, null);
}
void GetJournalEntryHeadersFromDbComplete(object sender, EntityResultsArgs<JournalViewItem> e)
{
if (e.Error != null)
{
string errMsg = e.Error.Message;
}
else
{
_journalHeaders = e.Results
.Select(
x => new JournalEntryHeader(x.JournalItemId,
x.ProjectName,
x.TopicName,
x.HeaderText,
x.EntryTypeName,
x.LastUpdatedOn)).ToList();
GetJournalEntryHeadersComplete(this, new JournalEntryHeaderItemsEventArgs(_journalHeaders));
}
}
What you need to do is the following, in the new JournalEntry() function you will need to set all the properties to the JournalViewItem object.
var journalEntry = Context.GetJournalViewItemsQuery()
.Where(i => i.JournalItemId == _journalEntryId)
.Select(x => new JournalEntry {
JournalEntryId = x.JournalItemId,
HeaderText = x.HeaderText,
JournalText = x.JournalText
//etc
}).Single();
I am just guessing the actual property names here as I am not familiar with what the JounralEntry object looks like.
EDIT: added {}
I created a ConsoleApp to test #JanR answer. It seems to be working correctly.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StackOverFlowConsoleApplication
{
class Program
{
static void Main(string[] args)
{
List<JournalViewItem> JournalViewItems = new List<JournalViewItem>()
{
new JournalViewItem(){JournalItemId =1, HeaderText="HeaderText", JournalText="JournalText", LastUpdatedOn= DateTime.Today, JournalItemTypeId=1},
};
int _journalEntryId = 1;
var journalEntry = JournalViewItems
.Where(i => i.JournalItemId == _journalEntryId)
.Select(x => new JournalEntry
{
JournalEntryNumber = x.JournalItemId,
HeaderText = x.HeaderText,
BodyText = x.JournalText,
LastUpdatedOn = x.LastUpdatedOn,
JournalEntryType = x.JournalItemTypeId
}).Single();
}
class JournalViewItem
{
public int JournalItemId { get; set; }
public string HeaderText { get; set; }
public string JournalText { get; set; }
public DateTime LastUpdatedOn { get; set; }
public int JournalItemTypeId { get; set; }
}
class JournalEntry
{
public int JournalEntryNumber { get; set; }
public string HeaderText { get; set; }
public string BodyText { get; set; }
public DateTime LastUpdatedOn { get; set; }
public int JournalEntryType { get; set; }
}
}
}
I looked into complx type a little bit. I tried the following code in my own project and was able to reproduce the error you mentioned:
var result = (from y in CS.PSMBIPMTTXLOGs select new PSMBIPMTCONTROL(){MBI_PMT_TX_ID = y.MBI_PMT_TX_ID}).ToList();
But when I changed it to return anonymous type, it worked:
var result = (from y in CS.PSMBIPMTTXLOGs select new {MBI_PMT_TX_ID = y.MBI_PMT_TX_ID}).ToList();
You mentioned that you have even tried creating an anonymous type instead of newing it into my DTO, but it still complains. Can you post your code for returning an anonymous type and the error message it gives? Thank you.
I found out the reason for my problem. I failed to mention (my apologies) that I'm working off generated code from WCF RIA Domain Services for Silverlight application. As such the Context.GetJournalViewItemsQuery() needs to be executed and THEN I can query the results on my callback method using the LINQ expression that #Chuck.Net and JanR have suggested.
You'll find the answer in the original post where I entered the question.

Resources