JSON returned data formatting - asp.net

I'm using code below to get JSON data:
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult getBranchViaJson()
{
Json(getBranchList(AppSession.BranchID.Value));
}
private object getBranchList(int n)
{
var mybranchList = from p in getBranchs(n)
select new { p.Code, p.Name };
return mybranchList.ToArray();
}
Client side retain value :
[{"Code":000,"Name":"Milan"},
{"Code":001,"Name":"Istanbul"},
{"Code":002,"Name":"Baku"},]
But I want to get like this:
[{000:"Milan"},{001:"Istanbul"},{002:"Baku"}]
What is the best way to do this?

First things first:
[{000:"Milan"},{001:"Istanbul"},{002:"Baku"}]
is invalid JSON. Properties must be quoted like so:
[{"000":"Milan"},{"001":"Istanbul"},{"002":"Baku"}]
In order to achieve this output you could use a Dictionary<string, string> that the JavaScriptSerializer will serialize to the desired output. So simply call the ToDictionary extension method on your model in order to convert it to a dictionary:
Like that:
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult getBranchViaJson()
{
var branches =
from p in getBranchs(AppSession.BranchID.Value)
select new { p.Code, p.Name };
var model = branches.ToDictionary(x => x.Code, x => x.Name);
return Json(new[] { model }, JsonRequestBehavior.AllowGet);
}
or if you want to keep your private method which returns an object you could make it return a dictionary:
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult getBranchViaJson()
{
return Json(getBranchList(AppSession.BranchID.Value), JsonRequestBehavior.AllowGet);
}
private object getBranchList(int n)
{
var mybranchList = from p in getBranchs(n)
select new { p.Code, p.Name };
return new[] { mybranchList.ToDictionary(x => x.Code, x => x.Name) };
}
Notice that I used new[] { model }. That's because otherwise the JavaScriptSerializer won't produce a javascript array as required but a simple javascript object.
Remark: notice that I have added JsonRequestBehavior.AllowGet so that this controller action can be consumed with a GET request which is disabled by default for actions returning JSON responses.

Related

is it a good idea to do transformation in a database model with ASP.Net

we are a small development team.
We develop in ASP.NET and we are starting to use generic controllers and services.
The goal is to have solid methods for things that are repetitive.
What we ask ourselves is if it is a good idea to do some transformation in the data models to allow us to reuse our functions that we know are working?
Exemple: we have a combobox and we want to manage the display and search. It's always the same and redundant.
This is my class
[Table("stage.Test")]
public partial class Test : IBaseEntity, ICombobox
{
public virtual Product Product { get; set; }
public string nom { get; set; }
public string prenom { get; set; }
public string title { get; set; }
[NotMapped]
public virtual string AffichageCombobox => nom + prenom;
[NotMapped]
public virtual string TexteRecherche => Product.Gabarit.Description;
}
as you can see i have two columns with the tag [NotMapped]. These are the columns in the interface ICombobox
public interface ICombobox
{
string AffichageCombobox { get;}
string TexteRecherche { get; }
}
this is the first service where I use one of my two columns which redirects to other columns. [We use the column "AffichageCombobox" from the model]
public List<ComboboxViewModel> GetComboboxViewModel(int? id, bool actifseulement, string text)
{
var query = _requestDatabaseService.GetComboboxQuery<T>(id, actifseulement, text);
var list = query.Select(table => new ComboboxViewModel
{
Id = table.Id,
AffichageCombobox = table.DateHFin == null ? table.AffichageCombobox : table.AffichageCombobox + " (inactif)"
}).ToList();
return list;
}
This is the RequestDatabaseService [We use the column "TexteRecherche" from the model]
public List<T> GetComboboxQuery<T>(int? id, bool actifseulement, string text) where T : class, IBaseEntity, ICombobox
{
text = text.ToLower();
var list = _dbContext.Set<T>()
.If(id.HasValue,
q => q.Where(x => x.Id == id))
.If(actifseulement,
q => q.Where(x => x.DateHFin == null))
.If(text != "",
q => q.Where(x => x.TexteRecherche.ToLower() == text))
.ToList();
return list;
}
As you can see, I am using an interface to add columns to redirect to the correct columns to my data model to avoid overriding my methods for two column.
Is it a good idea, a good practice ?
What do you think is the best practice if we want to do generic functions, but the columns are not called the same way?
Thank you!
Your solution has a lot of weaknesses
You have extended Model to handle specific UI cases. In my opinion it is bad practice.
Your virtual properties will not work in LINQ query. EF translates only Expression because it canot look into compiled property body.
What we can do here is simplifying of building such comboboxes. I have defind set fo extensions which can be reused for such scenarios. Sorry if there some mistakes, written from memory.
How it can be used:
Assuming that GetComboboxViewModel is not in generic class
public List<ComboboxViewModel> GetComboboxViewModel(int? id, bool actifseulement, string text)
{
// uncover DbContext. All that we need is IQueryable<Test>
var ctx = _requestDatabaseService.GetContext();
var query = ctx.Test.AsQueryable();
var comboItems = query
.FilterItems(id, actifseulement)
.GetComboboxQuery(text, e => e.Product.Gabarit.Description, e => e.nom + e.prenom)
.ToList();
return comboItems;
}
Think about this solution and yes, we can register somewhere pair of Lmbdas Dictionary<Type, (LambdaExpression: searchProp, LambdaExpression: displayProp)> and dynamically build call above.
Realisation:
public static class QueryableExtensions
{
// more simlified version for filtering
public static IQueryable<T> WhereIf(this IQueryable<T> query, bool condition, Expression<Func<T, bool>> predicate)
{
return condition ? query.Where(predicate) : query;
}
// handy function for filtering
public static IQueryable<T> FilterItems<T>(this IQueryable<T> query, int? id, bool onlyActive)
where T : IBaseEntity
{
query = query
.WhereIf(id.HasValue, x => x.Id == id)
.WhereIf(onlyActive, x => x.DateHFin == null)
return query;
}
// dynamic generation of filtering and projection
public static IQueryable<ComboboxViewModel> GetComboboxQuery<T>(this IQueryable<T> query, string text, Expression<Func<T, string>> searchProp, Expression<Func<T, string>> dsiplayProp)
where T : IBaseEntity
{
if (!string.IsNullOrEmpty(text))
{
text = text.ToLower();
// defining search pattern
// this also extension point, you may use here `Contains` or FullText search functions
Expression<Func<string, string, bool>> filterFunc = (s, t) => s.ToLower() == t;
// reusing parameter from searchProp lambda
var param = searchProp.Parameters[0];
// applying pattern to searchprop
var filterBody = ExpressionReplacer.GetBody(filterFunc, searchProp.Body, Expression.Constant(text));
// applying generated filter
var filterPredicate = Expression.Lambda<Func<T, bool>>(filterBody, param);
query = query.Where(filterPredicate);
}
// defining template for Select
Expression<Func<T, string, ComboboxViewModel>> createTemplate = (entity, dp) => new ComboboxViewModel
{
Id = entity.Id,
AffichageCombobox = entity.DateHFin == null ? dp : dp + " (inactif)"
};
// reusing parameter from dsiplayProp lambda
var entityParam = dsiplayProp.Parameters[0];
// injecting dsiplayProp into createTemplate
var selectBody = ExpressionReplacer.GetBody(createTemplate, entityParam, dsiplayProp.Body);
var selectLambda = Expression.Lambda<Func<T, ComboboxViewModel>>(selectBody, entityParam);
// applying projection
var comboQuery = query.Select(selectLambda);
return comboQuery;
}
// helper class for correcting expressions
class ExpressionReplacer : ExpressionVisitor
{
readonly IDictionary<Expression, Expression> _replaceMap;
public ExpressionReplacer(IDictionary<Expression, Expression> replaceMap)
{
_replaceMap = replaceMap ?? throw new ArgumentNullException(nameof(replaceMap));
}
public override Expression Visit(Expression exp)
{
if (exp != null && _replaceMap.TryGetValue(exp, out var replacement))
return replacement;
return base.Visit(exp);
}
public static Expression Replace(Expression expr, Expression toReplace, Expression toExpr)
{
return new ExpressionReplacer(new Dictionary<Expression, Expression> { { toReplace, toExpr } }).Visit(expr);
}
public static Expression Replace(Expression expr, IDictionary<Expression, Expression> replaceMap)
{
return new ExpressionReplacer(replaceMap).Visit(expr);
}
public static Expression GetBody(LambdaExpression lambda, params Expression[] toReplace)
{
if (lambda.Parameters.Count != toReplace.Length)
throw new InvalidOperationException();
return new ExpressionReplacer(Enumerable.Range(0, lambda.Parameters.Count)
.ToDictionary(i => (Expression) lambda.Parameters[i], i => toReplace[i])).Visit(lambda.Body);
}
}
}
Well, after writing this sample, I think, it can be cardinally simplified by using LINQKit. Will post another answer with LINQKit usage if you are interested,

How to declare public var and return in controller mvc

I have passed two arguments from view page to controller. but i dont know how to return this.."var Source". It should error show
[HttpPost]
public JsonResult FilterbyAutoComplete(string prefix,string filterBy)
{
VGLMSEntities2 db = new VGLMSEntities2();
var Source="";
if (filterBy == "Patient Name")
{
Source = db.Patient_Registeration.Where(m => m.PatientName.StartsWith(prefix)).Select(x => new { label = x.PatientName, val = x.PatientName }).ToList();
}
return Json(Source );
}
var keyword is just a syntactic sugar, it doesn't really exists, it just tells the compiler to take whatever on the right and use it the same.
I believe you may want to use the type 'object' instead for that case.
You can also just do
if (...)
return db.Patient_Registeration....
return Json(); // In case condition didn't catch
you can use dynamic
[HttpPost]
public JsonResult FilterbyAutoComplete(string prefix,string filterBy)
{
VGLMSEntities2 db = new VGLMSEntities2();
dynamic Source=null;
if (filterBy == "Patient Name")
{
Source = db.Patient_Registeration.Where(m => m.PatientName.StartsWith(prefix)).Select(x => new { label = x.PatientName, val = x.PatientName }).ToList();
}
return Json(Source );
}

ASP.NET RC2 - ModelState doesn't validate elements of collection

Let's say that I have simple model with required attribute above property.
public class User
{
[Required]
string Name {get;set;}
string Surname {get;set;}
}
When I POST/PUT only one instance of User and Name is empty it works pretty well. ModelState is not valid and contains error.
When I POST/PUT collection of objects User and in some of them Name is empty then ModelState is valid and it does not contain any validation errors.
Could you tell me what is wrong with it and why it concerns only collections? I noticed same behaviour when I have one object with relation one-many. Then collection within this object also is not validated by ModelState.
I don't want to validate required fields manually, it should work automatically.
You need to create a ActionFilter
public class ModelStateValidActionFilter : IAsyncActionFilter
{
public Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// Validate ICollection
if (context.ActionArguments.Count == 1 && context.ActionArguments.First().Value.GetType().IsListType())
{
foreach (var arg in (IList)context.ActionArguments.First().Value )
{
var parameters = arg.GetType().GetProperties();
foreach (var parameter in parameters)
{
var argument = context.ActionArguments.GetOrDefault(parameter.Name);
EvaluateValidationAttributes(parameter, argument, context.ModelState);
}
}
}
if (context.ModelState.IsValid)
{
return next();
}
context.Result = new BadRequestObjectResult(context.ModelState);
return Task.CompletedTask;
}
private void EvaluateValidationAttributes(PropertyInfo parameter, object argument, ModelStateDictionary modelState)
{
var validationAttributes = parameter.CustomAttributes;
foreach (var attributeData in validationAttributes)
{
var attributeInstance = parameter.GetCustomAttribute(attributeData.AttributeType);
var validationAttribute = attributeInstance as ValidationAttribute;
if (validationAttribute != null)
{
var isValid = validationAttribute.IsValid(argument);
if (!isValid)
{
modelState.AddModelError(parameter.Name, validationAttribute.FormatErrorMessage(parameter.Name));
}
}
}
}
and add it into your MVC options
services.AddMvc()
.AddMvcOptions(opts =>
{
opts.Filters.Add(new ModelStateValidActionFilter());
}

Inject TableName as Parameter for Update & Insert on GenericEntity in ServiceStack Ormlite

I have 3 tables of same structure so i have created the following entity using ServiceStack
public class GenericEntity
{
[Alias("COL_A")]
public string ColumnA { get; set; }
}
For retriving the results I use the following line of code. In it I pass the table name like "TableA"/"TableB" so that i can pull the appropriate results
db.Select<GenericEntity>(w => w.Where(whereExperssion).OrderBy(o => o.ColumnA).From("TableA"));
For delete i use the following code
db.Delete<GenericEntity>(w => w.Where(q => q.ColumnA == "A").From("TableA"));
With From() I can pass table name for SELECT & DELETE operations. Is there a similar way for Inserting and updating? The below is the snippet code I am using for update and insert
Insert
db.Insert(new GenericEntity() {});
Update
db.Update<GenericEntity>(new GenericEntity { ColumnA = "ModifiedData"},p => p.ColumnA == "OriginalData");
As you're wanting to this for multiple API's I've added a test showing how to achieve the desired behavior by extending OrmLite's API's with your own custom extension methods that modifies OrmLite's table metadata at runtime to add new API's that allow specifying the table name at runtime, i.e:
var tableName = "TableA"'
db.DropAndCreateTable<GenericEntity>(tableName);
db.Insert(tableName, new GenericEntity { Id = 1, ColumnA = "A" });
var rows = db.Select<GenericEntity>(tableName, q =>
q.Where(x => x.ColumnA == "A"));
rows.PrintDump();
db.Update(tableName, new GenericEntity { ColumnA = "B" },
where: q => q.ColumnA == "A");
rows = db.Select<GenericEntity>(tableName, q =>
q.Where(x => x.ColumnA == "B"));
rows.PrintDump();
With these extension methods:
public static class GenericTableExtensions
{
static object ExecWithAlias<T>(string table, Func<object> fn)
{
var modelDef = typeof(T).GetModelMetadata();
lock (modelDef) {
var hold = modelDef.Alias;
try {
modelDef.Alias = table;
return fn();
}
finally {
modelDef.Alias = hold;
}
}
}
public static void DropAndCreateTable<T>(this IDbConnection db, string table) {
ExecWithAlias<T>(table, () => { db.DropAndCreateTable<T>(); return null; });
}
public static long Insert<T>(this IDbConnection db, string table, T obj, bool selectIdentity = false) {
return (long)ExecWithAlias<T>(table, () => db.Insert(obj, selectIdentity));
}
public static List<T> Select<T>(this IDbConnection db, string table, Func<SqlExpression<T>, SqlExpression<T>> expression) {
return (List<T>)ExecWithAlias<T>(table, () => db.Select(expression));
}
public static int Update<T>(this IDbConnection db, string table, T item, Expression<Func<T, bool>> where) {
return (int)ExecWithAlias<T>(table, () => db.Update(item, where));
}
}
Adding your own extension methods in this way allows you to extend OrmLite with your own idiomatic API's given that OrmLite is itself just a suite of extension methods over ADO.NET's IDbConnection.

Kendo dropdownlist produces TypeError: n.slice is not a function

Do I need to define the schema? If so, what should that look like? My searches for this seem to only turn up js solutions, I'm looking for the syntax to define it in the editortemplate.
Shared/editortemplate:
#(
Html.Kendo().DropDownList()
.Name("SearchFunction")
.DataTextField("SearchFunctionDesc")
.DataValueField("SearchFunctionCode")
.DataSource(source =>
{
source.Read(read => {
read.Action("GetSearchFunctions", "User");
});
})
.OptionLabel("--Select a Search Function--")
.AutoBind(false)
)
In the controller:
public JsonResult GetSearchFunctions([DataSourceRequest] DataSourceRequest request)
{
var searchFuncs = AdminService.GetSearchFunctions();
DataSourceResult result = searchFuncs.ToDataSourceResult(request);
return Json(result, JsonRequestBehavior.AllowGet);
}
And then my Dapper db query:
var result = new List<SearchFunction>();
using (var conn = new OracleConnection(DatabaseConnectionString))
{
conn.Open();
string query = "select FUNCTION_ID, SEARCH_FUNCTION_CD, " +
"SEARCH_FUNCTION_DESC, IS_ACTIVE " +
"from TBL_SEARCH_FUNCTIONS ";
result = conn.Query(query)
.Select(s => new SearchFunction
{
FunctionId = (int)s.FUNCTION_ID,
SearchFunctionCode = s.SEARCH_FUNCTION_CD,
SearchFunctionDesc = s.SEARCH_FUNCTION_DESC,
Active = s.IS_ACTIVE
}).ToList<SearchFunction>();
conn.Close();
return result;
}
Rewrite your controller method like this:
public JsonResult GetSearchFunctions()
{
var searchFuncs = cmsViewAdminService.GetSearchFunctions();
return Json(searchFuncs, JsonRequestBehavior.AllowGet);
}
That should simplify that method as you don't need the DataSourceRequest (as #CSharper mentioned in the comment). Kendo DropDownLists, unlike the grids, don't require the DataSourceRequest class. This way, you can call the same JsonResult from a jQuery Ajax method if you needed to do so.
You need to return a pure collection from json something that looks like that
{[
{"Id":2,"Name":"some"},
{"Id":3,"Name":"som2"}
]}
If you use ModelView and lambda then you might also try to the code below:
Assume you have a city dropdownlist retrieving data from reference table (populated to CityViewModel):
public JsonResult GetCities()
{
var dataContext = new EFDbContext();
var cities = dataContext.Cities.Select(c => new CityViewModel
{
ID = c.ID,
Name = c.Name
});
return Json(cities, JsonRequestBehavior.AllowGet);
}

Resources