I use Generic and Reflection, so the main problem is add several fields. When i use this code with one field it OK but when i try somehow add new fields it doesn't work:
public static ISearchResponse<T> PartSearch<T>(ElasticClient client, string query, List<string> fieldList = null, int from = 0, int size = 1) where T : class
{
if (client == null)
throw new ArgumentNullException();
if (String.IsNullOrEmpty(query))
throw new ArgumentNullException();
ISearchResponse<T> results;
if (fieldList == null)
{
results = client.Search<T>(q =>
q.Query(q =>
q.QueryString(qs => qs.Query(query))
).From(from).Size(size)
);
}
else
{
results = client.Search<T>(q =>
q.Query(q => q
.QueryString(qs =>
{
//This place where i try to add several fields
List<Field> fildArray = new List<Field>();
foreach (var arg in fieldList)
{
var fieldString = new Field(typeof(T).GetProperty(arg));
fildArray.Add(fieldString);
}
qs.Fields(f => f.Field(fildArray));
qs.Query(query);
return qs;
})
).From(from).Size(size)
);
}
return results;
}
I created an example using Lenient() that can help you with your question:
https://github.com/hgmauri/elasticsearch-with-nest/blob/master/src/Sample.Elasticsearch.Domain/Abstractions/NestExtensions.cs
Problem was in one QueryString parameter Lenient:
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html
Fixed this by setting it on True.
Related
I have 2 areas in my ASP.NET Core 3.1 API and models in each of them. I'm trying to produce 2 swagger documents, each for its area.
Operations are filtered based on IOperationProcessor, and all operations are correct. However, each document includes all documents from both areas.
What is the way to control which models included in which document?
This is what I have at the moment:
services.AddOpenApiDocument(swagger =>
{
swagger.DocumentName = "admin";
swagger.OperationProcessors.Add(new Swagger.AdminOperationProcessor());
swagger.SchemaNameGenerator = new Swagger.SchemaNameGenerator();
});
services.AddOpenApiDocument(openApi =>
{
openApi.DocumentName = "public";
openApi.OperationProcessors.Add(new Swagger.PublicOperationProcessor());
openApi.SchemaNameGenerator = new Swagger.SchemaNameGenerator();
openApi.PostProcess = (x) =>
{
};
});
After looking for ages, what I had to do is a bit of a botched solution. Using ISchemaNameGenerator replace not desired names into something else (I replace "." to "_"). Then using PostProcess remove them from generated schema. ExcludedTypeNames doesn't work for some reason.
var excludedList = new List<string>();
// this is called first
settings.SchemaNameGenerator = new SchemaNameGenerator(x =>
{
if (!typeNamespaces.Any(n => x.FullName.StartsWith(n)))
{
excludedList.Add(x.FullName);
}
return !typeNamespaces.Any(n => x.FullName.StartsWith(n));
});
// Post process relies on excluded list, otherwise it won't work
settings.PostProcess = (doc) =>
{
foreach (var exItem in excludedList)
{
var formatted = exItem.Replace(".", "_");
if (doc.Definitions.ContainsKey(formatted))
{
doc.Definitions.Remove(formatted);
}
}
};
The SchemaNameGenerator is:
public class SchemaNameGenerator : ISchemaNameGenerator
{
private Func<Type, bool> excludePredicate;
public SchemaNameGenerator(Func<Type, bool> excludePredicate = null)
{
this.excludePredicate = excludePredicate;
}
public string Generate(Type type)
{
var displayAttr = type
.GetCustomAttributes(typeof(DisplayNameAttribute), true)
.Cast<DisplayNameAttribute>()
.FirstOrDefault();
if (excludePredicate != null)
{
if (excludePredicate(type))
{
return type.FullName.Replace(".", "_");
}
}
return displayAttr?.DisplayName ?? type.Name;
}
}
If anybody has a better idea, please let me know.
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 );
}
I want to convert the linq query results to datatable so that I can assign datatable to GridView to show it on asp page.
However I am not able to convert the results to datatable, I am not getting CopyToTable() method in my code.
please advise what am I doing wrong here?
var gradeData = (from data in oAngieCtxt.prc_ShopInstanceCustomersData(Convert.ToInt32(this.ShopInstanceID), 10000, false)
.Where( row => row.RecievedPoints != "n/a" )
.GroupBy(row => new { row.Name })
.Select(g => new GroupedPoints()
{
Name = g.Key.Name,
TotalPoints = g.Sum(x => Convert.ToDouble(x.RecievedPoints) * (x.Weightage.ToString() == "0.00" ? 1 : Convert.ToDouble(x.Weightage)))
})
select data).ToList();
DataTable dt = gradeData --gradeData.CopyToTable()
Note: reference to dataextentions dll is available.
Thanks in advance
You should get DataTableExtensions.CopyToDataTable
Remove ToList().
CopyToDataTable is an IEnumerable<DataRow> extension (unfortunately).
There is a solution with custom CopyToDataTable extension method below.
var gradeData = (from data in oAngieCtxt.prc_ShopInstanceCustomersData(
Convert.ToInt32(this.ShopInstanceID), 10000, false)
.Where( row => row.RecievedPoints != "n/a" )
.GroupBy(row => new { row.Name })
.Select(g => new
{
Name = g.Key.Name,
TotalPoints = g.Sum(x => Convert.ToDouble(x.RecievedPoints)
* (x.Weightage.ToString() == "0.00" ? 1
: Convert.ToDouble(x.Weightage)))
})
select data);
var dt = gradeData.CopyToDataTable();
Edit:
Here is a more useful implementation of CopyToDataTable There is no type constraint to DataRow.
public static class DataSetLinqOperators
{
public static DataTable CopyToDataTable<T>(this IEnumerable<T> source)
{
//you find the ObjectShredder implementation on the blog wich was linked.
return new ObjectShredder<T>().Shred(source, null, null);
}
public static DataTable CopyToDataTable<T>(this IEnumerable<T> source,
DataTable table, LoadOption? options)
{
return new ObjectShredder<T>().Shred(source, table, options);
}
}
First declare a new DataTable and add columns, in this :
DataTable dt = new DataTable();
dt.Columns.Add("FirstName");
dt.Columns.Add("LastName");
DataRow row = null;
Now I simply iterate through the query and fill a DataTable:
foreach (var rowObj in query)
{
row = dt.NewRow();
dt.Rows.Add(rowObj.FirstName, rowObj.LastName);
}
If you want to have you own extension method then you could always do something like this:
public static DataTable ToDataTable<T>(this IQueryable items)
{
Type type = typeof(T);
var props = TypeDescriptor.GetProperties(type)
.Cast<PropertyDescriptor>()
.Where(propertyInfo => propertyInfo.PropertyType.Namespace.Equals("System"))
.Where(propertyInfo => propertyInfo.IsReadOnly == false)
.ToArray();
var table = new DataTable();
foreach (var propertyInfo in props)
{
table.Columns.Add(propertyInfo.Name, Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType);
}
foreach (var item in items)
{
table.Rows.Add(props.Select(property => property.GetValue(item)).ToArray());
}
return table;
}
You will need to reference both of these
using System.ComponentModel;
using System.Data;
Consider following code:
My problem is:
1) I can't seem to cast the errors to HttpContent
2) I can't use the CreateContent extension method as this doesn't exist on the context.Response.Content.CreateContent
The example here only seems to provide StringContent and I'd like to be able to pass the content as a JsobObject:
http://www.asp.net/web-api/overview/web-api-routing-and-actions/exception-handling
public class ServiceLayerExceptionFilter : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Response == null)
{
var exception = context.Exception as ModelValidationException;
if ( exception != null )
{
var modelState = new ModelStateDictionary();
modelState.AddModelError(exception.Key, exception.Description);
var errors = modelState.SelectMany(x => x.Value.Errors).Select(x => x.ErrorMessage);
// Cannot cast errors to HttpContent??
// var resp = new HttpResponseMessage(HttpStatusCode.BadRequest) {Content = errors};
// throw new HttpResponseException(resp);
// Cannot create response from extension method??
//context.Response.Content.CreateContent
}
else
{
context.Response = new HttpResponseMessage(context.Exception.ConvertToHttpStatus());
}
}
base.OnException(context);
}
}
context.Response = new HttpResponseMessage(context.Exception.ConvertToHttpStatus());
context.Response.Content = new StringContent("Hello World");
you also have the possibility to use the CreateResponse (added in RC to replace the generic HttpResponseMessage<T> class that no longer exists) method if you want to pass complex objects:
context.Response = context.Request.CreateResponse(
context.Exception.ConvertToHttpStatus(),
new MyViewModel { Foo = "bar" }
);
I have the following bits of code in my accountRepository
public string[] GetRolesForUser(string email)
{
// User rolesUser = FindByMail(email);
IEnumerable<UserRole> RoleList = context.UserRolesSet.Where(u => u.user_id == 1).AsEnumerable();
string[] arr1 = new string[RoleList.Count()];
int i = 0;
foreach (UserRole r in RoleList)
{
arr1[i] = r.roles.name;
i++;
}
return arr1;
}
This should work but it doesn't. When it looping through the foreach loop it throws me this error:
Exception Details: MySql.Data.MySqlClient.MySqlException: There is already an open DataReader associated with this Connection which must be closed first.
Is my foreach loop wrong?
You could simplify the method:
IEnumerable<UserRole> RoleList = context.UserRolesSet.Where(u => u.user_id == 1);
return RoleList.Select(x => x.roles.name).ToArray();
Try the following code. Using ToArray makes sure it populates all of the UserRoles before hand so it'll be finished with the DataReader.
public string[] GetRolesForUser(string email)
{
// User rolesUser = FindByMail(email);
IEnumerable<UserRole> RoleList = context.UserRolesSet.Where(u => u.user_id == 1).ToArray();
string[] arr1 = new string[RoleList.Count()];
int i = 0;
foreach (UserRole r in RoleList)
{
arr1[i] = r.roles.name;
i++;
}
return arr1;
}