kendo-ui mvc autocomplete does not display results - kendo-ui

I was able to get a working version using the js version dojo autocomplate but I need it to work using the MVC version. I added DataSourceRequest in the controller as suggested below and changed a couple more items that got rid of the js error I was getting:
//Fixed, added the schema definition
Uncaught TypeError: e.slice is not a function
It appears to work as I trace it through the controller, which returns the expected json (below) but it doesn't finish wiring up as the spinner hangs and the results aren't displayed.
{
"Data": [{
"EmployeeId": 2147483649,
"EmployeeName": "Emily F Johnston",
"Rating": 75.0,
"LastAudited": null
}, {
"EmployeeId": 2147483687,
"EmployeeName": "Joshua Smith",
"Rating": 80.2,
"LastAudited": null
}, {
"EmployeeId": 2147483656,
"EmployeeName": "Thomas F Dunn",
"Rating": 45.0,
"LastAudited": "\/Date(1463893200000)\/"
}, {
"EmployeeId": 2147483660,
"EmployeeName": "Marjon Christine Marik",
"Rating": 88.0,
"LastAudited": null
}],
"Total": 4,
"AggregateResults": null,
"Errors": null
}
The controller:
[HttpPost]
public ActionResult EmployeeLookup(string text, [DataSourceRequest] DataSourceRequest request)
{
var filter = request?.Filters.FirstOrDefault() as FilterDescriptor;
var search = string.Empty;
if (filter != null)
{
search = filter.Value?.ToString() ?? string.Empty;
}
var employees = new List<EmployeeLookupResultEntryViewModel>();
var results = _employeeService.EmployeeLookup(search);
if (results == null)
return Json(employees.ToDataSourceResult(request));
return Json(results.ToDataSourceResult(request));
}
The autocomplete definition:
Also, I found this doco from Telerik that looks very similar to my use case Telerik Custom Template but it lacks showing the controller methods so I can't verify how they wired it up.
#(Html.Kendo().AutoComplete()
.Name("Employees")
.DataTextField("EmployeeName")
.Placeholder("Search Employee")
.Filter("contains")
.IgnoreCase(true)
.MinLength(3)
.Delay(300)
.HighlightFirst(true)
.HtmlAttributes(new { style = "width:100%" })
.NoDataTemplate("Employee Not Found")
.DataSource(dataSource =>
{
dataSource.Custom()
.ServerFiltering(true)
.Type("aspnetmvc-ajax")
.Transport(transport =>
{
transport.Read("EmployeeLookup", "Employee", new {area = "Client"});
})
.Schema(schema => {schema.Data("Data");});
})
.HeaderTemplate("<div style=\"width: 400px;\" class=\"dropdown-header k-widget k-header\">" +
"<span>Id</span>" +
"<span>Name</span>" +
"<span>Pwc Rating" +
"<span>Last Audited</span>" +
"</div>")
.Template("<span style=\"width: 50px;\">#: data.EmployeeId #</span><span class=\"cell\">#: data.EmployeeName #</span><span class=\"cell\">#: data.PwcRating #</span><span class=\"cell\">#: data.LastAudited #</span>")
)
I seem to be missing some config setting in the html because the json/datasouce is being returned, similarly to what the documentation states...yet the widget can't wire it up.

You have enabled server filtering, which is significantly more complex than you've implemented
If you intended to enable this feature there are three things you need to do
Add Kendo ASP.NET MVC libraries to your project
Change your datasource type to be aspnetmvc-ajax:
Rework your action to use DataSourceRequest in your controller per this example. The DataSourceRequest attribute is NOT optional
public ActionResult Products_Read([DataSourceRequest] DataSourceRequest request)
{
return Json(productService.Read().ToDataSourceResult(request));
}

Related

How do you get the property value from a FHIR property using FhirClient

I am using the following code to call the NHS Retrieve Reference Data method
var result = await fhirClient.ReadAsync<CodeSystem>(url);
which returns the following Json (this is a snippet of the full json)
concept": [
{
"code": "BOOKED_CLINICAL_NEED",
"display": "Booked more urgently due to clinical need",
"property": [
{
"code": "effectiveFrom",
"valueDateTime": "2019-07-23T17:09:56.000Z"
},
{
"code": "commentIsMandatory",
"valueBoolean": true
},
{
"code": "canCancelAppointment",
"valueBoolean": false
}
]
}
I have used the GetExtensionValue method for other calls when the data is within an extension but I can't find a similar method for properties.
Is there a simple method or do I need to just cast into the required type manually?
Thanks in advance
There is no convenience method for this. However, the properties per concept are a list, so you could for example iterate over the concepts and select the properties with boolean values using regular list methods:
foreach (var c in myCodeSystem.Concept)
{
var booleanProperties = c.Property.Where(p => (p.Value.TypeName == "boolean"));
// do something with these properties
}
or find all concepts that have a boolean property:
var conceptsWithDateTimeProperties = myCodeSystem.Concept.Where(c => c.Property.Exists(p => (p.Value.TypeName == "dateTime")));
Of course you can make your selections as specific as you need.

Fluent Validation and ASP.NET Core 6 Web API

I am new to fluent validation and also a beginner in Web API. I have been working on a dummy project to learn and your advice will be much appreciated. After following the FluentValidation website, I was able to successfully implement fluent validation.
However, my response body looks very different and contains a lot of information. Is it possible to have a regular response body with validation errors?
I will put down the steps I took to implement fluent validation. your advice and help are much appreciated. I am using manual validation because based on the fluent validation website they are not supporting the auto validation anymore.
In the program file, I added
builder.Services.AddValidatorsFromAssemblyContaining<CityValidator>();
Then I added a class that validated my City class which has two properties Name and Description:
public class CityValidator : AbstractValidator<City>
{
public CityValidator()
{
RuleFor(x => x.Name)
.NotNull()
.NotEmpty()
.WithMessage("Please specify a name");
RuleFor(x => x.Description)
.NotNull()
.NotEmpty()
.WithMessage("Please specify a Description");
}
}
In my CitiesController constructor I injected Validator<City> validator; and in my action, I am using this code:
ValidationResult result = await _validator.ValidateAsync(city);
if (!result.IsValid)
{
result.AddToModelState(this.ModelState);
return BadRequest(result);
}
The AddToModelState is an extension method
public static void AddToModelState(this ValidationResult result, ModelStateDictionary modelState)
{
if (!result.IsValid)
{
foreach (var error in result.Errors)
{
modelState.AddModelError(error.PropertyName, error.ErrorMessage);
}
}
}
On post, I am getting the response as
{
"isValid": false,
"errors": [
{
"propertyName": "Name",
"errorMessage": "Please specify a name",
"attemptedValue": "",
"customState": null,
"severity": 0,
"errorCode": "NotEmptyValidator",
"formattedMessagePlaceholderValues": {
"PropertyName": "Name",
"PropertyValue": ""
}
},
{
"propertyName": "Description",
"errorMessage": "Please specify a name",
"attemptedValue": "",
"customState": null,
"severity": 0,
"errorCode": "NotEmptyValidator",
"formattedMessagePlaceholderValues": {
"PropertyName": "Description",
"PropertyValue": ""
}
}
],
"ruleSetsExecuted": [
"default"
]
}
While the regular response without Fluent Validation looks like this:
{
"errors": {
"": [
"A non-empty request body is required."
],
"pointofInterest": [
"The pointofInterest field is required."
]
},
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-1a68c87bda2ffb8de50b7d2888b32d02-94d30c7679aec10b-00"
}
The question: is there a way from the use the fluent validation and get the response format like
{
"errors": {
"": [
"A non-empty request body is required."
],
"pointofInterest": [
"The pointofInterest field is required."
]
},
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-1a68c87bda2ffb8de50b7d2888b32d02-94d30c7679aec10b-00"
}
Thank you for your time.
Updated ans:
with your code, you can simply replace.
return BadRequest(result); // replace this line with below line.
return ValidationProblem(ModelState);
then you get same format as required.
------------------------*----------------------------------------
Please ignore this for manual validation.
You don't need explicit validation call.
this code is not required:
ValidationResult result = await _validator.ValidateAsync(city);
if (!result.IsValid)
{
result.AddToModelState(this.ModelState);
return BadRequest(result);
}
it will auto validate the model using your custom validator.
you simply need this
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
and it will give you errors in the require format.
if(!result.IsValid)
{
result.AddToModelState(this.ModelState);
return ValidationProblem(ModelState);
}

.NET Core 3.1 API works fine locally but doesn't after deployment

In a Web-Application, written in C# in .NET Core 3.1, i want to Display a Datatable of all the Blobs in one of our Company's Azure Blob Storages. For this i'm using Datatables.net in the Frontend with Ajax-Calls which target a selfwritten API in the same Web-App. The API should get all the searched Blobs, format them for easier viewing and then give them back to the Table. Locally it really works like a charm. However, soon after deployment i noticed that the Ajax-Call just simply returns a 404 Response.
For reference:
My API-Controller
[Route("Blob/api/[controller]")]
[ApiController]
public class BlobsController : ControllerBase
{
private readonly string _connectionString;
private readonly string _container;
private readonly BlobContainerClient _client;
public BlobsController(IConfiguration configuration)
{
IEnumerable<IConfigurationSection> _blobStorageSection = configuration.GetSection("BlobStorage").GetChildren();
_connectionString = _blobStorageSection.Single(e => e.Key == "ConnectionString").Value;
_container = _blobStorageSection.Single(e => e.Key == "ContainerName").Value;
_client = new BlobContainerClient(_connectionString, _container);
}
[HttpGet("{EncodedDelimiter}/{EncodedPrefix}")]
public ActionResult GetBlobs(string EncodedDelimiter, string EncodedPrefix)
{
if (! StorageIsAvailable())
return NotFound();
string Delimiter = WebUtility.UrlDecode(EncodedDelimiter);
string Prefix = WebUtility.UrlDecode(EncodedPrefix);
Pageable<BlobHierarchyItem> BlobHierarchy = _client.GetBlobsByHierarchy(delimiter: Delimiter, prefix: Prefix);
return Ok(EnrichBlobList(BlobHierarchy));
}
[HttpGet("init/{EncodedDelimiter}")]
public ActionResult Initialize(string EncodedDelimiter)
{
if (! StorageIsAvailable())
return NotFound();
string Delimiter = WebUtility.UrlDecode(EncodedDelimiter);
Pageable<BlobHierarchyItem> BlobHierarchy = _client.GetBlobsByHierarchy(delimiter: Delimiter);
return Ok(EnrichBlobList(BlobHierarchy));
}
Here the Ajax-Call Snippet
var Table = $("#BlobTable").DataTable({
ajax:{
url: "api/Blobs/init/%2F",
dataSrc: ""
},
processing: true,
columnDefs:[
{
"targets": 0,
"data": "standartizedName",
},
{
"targets": 1,
"data": null,
"render": function(full){
return renderTyp(full);
},
"width": "10%"
},
{
"targets": 2,
"data": null,
"render": function(full){
return renderDatum(full);
},
"width": "15%"
},
{
"targets": 3,
"data": null,
"render": function(full){
return renderAction(full);
},
"orderable": false,
"searchable": false,
"width": "10%"
}
],
order:[[1, "desc"]],
pageLength: 50
});
And bc i have seen similar Problems where the Source-Problem was in StartUp:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TestDbcontext>(options => options.UseSqlServer(Configuration.GetConnectionString("TestDB"),
sqlServerOptionsAction: sqlOptions =>
{
sqlOptions.EnableRetryOnFailure(
maxRetryCount: 10,
maxRetryDelay: TimeSpan.FromMinutes(5),
errorNumbersToAdd: null
);
}));
if (Env.IsDevelopment())
{
UseFakeAuthenticationAndAuthorization(services);
//UseAuthenticationAndAuthorization(services, Configuration);
}
else
{
//UseFakeAuthenticationAndAuthorization(services);
UseAuthenticationAndAuthorization(services, Configuration);
}
services.AddControllersWithViews();
RepositoriesTestGUI(services);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Home}/{id?}");
});
}
Has someone else an Idea what could be the Problem? An API-Call is an absolute Necessity since the Storage contains 70k Files
EDIT:
By Request here are the Network Details
NetworkDetails
Bc this is my first Post i can't put embedded Pictures in apparently
The root cause of this problem is not having permission to access. The easiest way to test is to change the access level to Container.
My test steps:
Access a picture in container( Blob or Container access level ).
Uri like:
https://testaccount.blob.core.windows.net/testblob/SignalR.png
Result
Access a picture in container( private access level ). We will reproduce the issue.
Suggestion
We can write a method to generate sas token to access the files. You can refer my code or read the official doc.

Passing multiple parameters to web API GET method

I have created a WEB API using MySQL Database. The API works as expected for now. I sent a meter serial number and a date time parameter and then GET the expected result. Below is my controller
public MDCEntities medEntitites = new MDCEntities();
public HttpResponseMessage GetByMsn(string msn, DateTime dt)
{
try
{
var before = dt.AddMinutes(-5);
var after = dt.AddMinutes(5);
var result = medEntitites.tj_xhqd
.Where(m =>
m.zdjh == msn &&
m.sjsj >= before &&
m.sjsj <= after).Select(m => new { MSN = m.zdjh, DateTime = m.sjsj, Signal_Strength = m.xhqd }).Distinct();
return Request.CreateResponse(HttpStatusCode.Found, result);
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
}
}
Below is my WebApiConfig file
config.Routes.MapHttpRoute(
name: "GetByMsn",
routeTemplate: "api/{controller}/{action}/{msn}/{dt}",
defaults: null,
constraints: new { msn = #"^[0-9]+$" , dt = #"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$" }
);
The URL is http://localhost:14909/api/meters/GetByMsn/002999000171/2017-10-10T10:08:20
The response I GET is
[{
"MSN": "002999000171",
"DateTime": "2017-10-10T10:04:39",
"Signal_Strength": "20"
},
{
"MSN": "002999000171",
"DateTime": "2017-10-10T10:06:35",
"Signal_Strength": "19"
},
{
"MSN": "002999000171",
"DateTime": "2017-10-10T10:08:31",
"Signal_Strength": "20"
},
{
"MSN": "002999000171",
"DateTime": "2017-10-10T10:10:27",
"Signal_Strength": "20"
},
{
"MSN": "002999000171",
"DateTime": "2017-10-10T10:12:23",
"Signal_Strength": "20"
}]
This all scenario works when a single serial number is passed. But at client side there would be more than one different serial numbers. For this I had to make my method to work both for one and more than one serial numbers provided the date time will be the same for all.
One solution is to create a new method a pass the multiple serial number strings, but this will not help because the number of serial numbers are dynamic i.e. they may be one, two to 100's. So setting a hard coded method won't be a solution.
I have searched for it but most of the times I have found the static method again and again. But this solution looks some what helpful but again I don't know whether it will work or not.
Any help would be highly appreciated.
You can pass a custom model to an action method, but I suggest not using the GET for you task because GET does not have a body.
Instead, use the SEARCH verb and put the list of serials number and the date inside a custom model in the body.
public class MeterSearchModel
{
public List<string> Serials {get;set;}
public DateTime Date {get;set;}
}
In .NET Core 2 your controller would have something like -
[AcceptVerbs("SEARCH")]
public async Task<IActionResult> Search([FromBody] MeterSearchModel model)
{
//..perform search
}

How do I return only selected certain fields in Strapi?

Pretty straightforward (I hope). I'd like to be able to use the API endpoint and have it only return specified fields. I.E. something like this
http://localhost:1337/api/reference?select=["name"]
Would ideally return something of the form
[{"name": "Ref1"}]
Unfortunately that is not the case, and in actuality it returns the following.
[
{
"contributors": [
{
"username": "aduensing",
"email": "standin#gmail.com",
"lang": "en_US",
"template": "default",
"id_ref": "1",
"provider": "local",
"id": 1,
"createdAt": "2016-07-28T19:39:09.349Z",
"updatedAt": "2016-07-28T19:39:09.360Z"
}
],
"createdBy": {
"username": "aduensing",
"email": "standin#gmail.com",
"lang": "en_US",
"template": "default",
"id_ref": "1",
"provider": "local",
"id": 1,
"createdAt": "2016-07-28T19:39:09.349Z",
"updatedAt": "2016-07-28T19:39:09.360Z"
},
"updatedBy": {
"username": "aduensing",
"email": "standin#gmail.com",
"lang": "en_US",
"template": "default",
"id_ref": "1",
"provider": "local",
"id": 1,
"createdAt": "2016-07-28T19:39:09.349Z",
"updatedAt": "2016-07-28T19:39:09.360Z"
},
"question": {
"createdBy": 1,
"createdAt": "2016-07-28T19:41:33.152Z",
"template": "default",
"lang": "en_US",
"name": "My Question",
"content": "Cool stuff, huh?",
"updatedBy": 1,
"updatedAt": "2016-07-28T19:45:02.893Z",
"id": "579a5ff83af4445c179bd8a9"
},
"createdAt": "2016-07-28T19:44:31.516Z",
"template": "default",
"lang": "en_US",
"name": "Ref1",
"link": "Google",
"priority": 1,
"updatedAt": "2016-07-28T19:45:02.952Z",
"id": "579a60ab5c8592c01f946cb5"
}
]
This immediately becomes problematic in any real world context if I decide to load 10, 20, 30, or more records at once, I and end up loading 50 times the data I needed. More bandwidth is used up, slower load times, etc.
How I solved this:
Create custom controller action (for example, 'findPaths')
in contributor/controllers/contributor.js
module.exports = {
findPaths: async ctx => {
const result = await strapi
.query('contributor')
.model.fetchAll({ columns: ['slug'] }) // here we wait for one column only
ctx.send(result);
}
}
Add custom route (for example 'paths')
in contributor/config/routes.json
{
"method": "GET",
"path": "/contributors/paths",
"handler": "contributor.findPaths",
"config": {
"policies": []
}
},
Add permission in admin panel for Contributor entity, path action
That's it. Now it shows only slug field from all contributor's records.
http://your-host:1337/contributors/paths
Here is how you can return specific fields and also exclude the relations to optimize the response.
async list (ctx) {
const result = await strapi.query('article').model.query(qb => {
qb.select('id', 'title', 'link', 'content');
}).fetchAll({
withRelated: []
}).catch(e => {
console.error(e)
});
if(result) {
ctx.send(result);
} else {
ctx.send({"statusCode": 404, "error": "Not Found", "message": "Not Found"});
}
}
I know this is old thread but I just run into exactly same problem and I could not find any solution. Nothing in the docs or anywhere else.
After a few minutes of console logging and playing with service I was able to filter my fields using following piece of code:
const q = Post
.find()
.sort(filters.sort)
.skip(filters.start)
.limit(filters.limit)
.populate(populate);
return filterFields(q, ['title', 'content']);
where filterFields is following function:
function filterFields(q, fields) {
q._fields = fields;
return q;
}
It is kinda dirty solution and I haven't figured out how to apply this to included relation entites yet but I hope it could help somebody looking for solution of this problem.
I'm not sure why strapi does not support this since it is clearly capable of filtering the fields when they are explicitly set. it would be nice to use it like this:
return Post
.find()
.fields(['title', 'content'])
.sort(filters.sort)
.skip(filters.start)
.limit(filters.limit)
.populate(populate);
It would be better to have the query select the fields rather than relying on node to remove content. However, I have found this to be useful in some situations and thought I would share. The strapi sanitizeEntity function can include extra options, one of which allows you only include fields you need. Similar to what manually deleting the fields but a more reusable function to do so.
const { sanitizeEntity } = require('strapi-utils');
let entities = await strapi.query('posts').find({ parent: parent.id })
return entities.map(entity => {
return sanitizeEntity(entity, {
model: strapi.models['posts'],
includeFields: ['id', 'name', 'title', 'type', 'parent', 'userType']
});
});
This feature is not implemented in Strapi yet. To compensate, the best option for you is probably to use GraphQL (http://strapi.io/documentation/graphql).
Feel free to create an issue or to submit a pull request: https://github.com/wistityhq/strapi
You can use the select function if you are using MongoDB Database:
await strapi.query('game-category').model.find().select(["Code"])
As you can see, I have a model called game-category and I just need the "Code" field so I used the Select function.
In the current strapi version (3.x, not sure about previous ones) this can be achieved using the select method in custom queries, regardless of which ORM is being used.
SQL example:
const restaurant = await strapi
.query('restaurant')
.model.query((qb) => {
qb.where('id', 1);
qb.select('name');
})
.fetch();
not very beautiful,but you can delete it before return.
ref here:
https://strapi.io/documentation/developer-docs/latest/guides/custom-data-response.html#apply-our-changes
const { sanitizeEntity } = require('strapi-utils');
module.exports = {
async find(ctx) {
let entities;
if (ctx.query._q) {
entities = await strapi.services.restaurant.search(ctx.query);
} else {
entities = await strapi.services.restaurant.find(ctx.query);
}
return entities.map(entity => {
const restaurant = sanitizeEntity(entity, {
model: strapi.models.restaurant,
});
if (restaurant.chef && restaurant.chef.email) {
**delete restaurant.chef.email;**
}
return restaurant;
});
},
};
yeah,I remember another way.
you can use the attribute in xx.settings.json file.
ref:
model-options
{
"options": {
"timestamps": true,
"privateAttributes": ["id", "created_at"], <-this is fields you dont want to return
"populateCreatorFields": true <- this is the system fields,set false to not return
}
}
You can override the default strapi entity response of:-
entity = await strapi.services.weeklyplans.create(add_plan);
return sanitizeEntity(entity, { model: strapi.models.weeklyplans });
By using:-
ctx.response.body = {
status: "your API status",
message: "Your own message"
}
Using ctx object, we can choose the fields we wanted to display as object.
And no need to return anything. Place the ctx.response.body where the response has to be sent when the condition fulfilled.
It is now 2023, and for a little while it has been possible to do this using the fields parameter:
http://localhost:1337/api/reference?fields[0]=name&fields[1]=something

Resources