Azure search document results is not binding to model - c#

trying to use azure search documents and bind to a specific model
Model
/// <summary>
/// AzureSearchReturnModel
/// </summary>
public class AzureSearchReturnModel
{
/*// <summary>
/// Gets or sets the module identifier.
/// </summary>
/// <value>
/// The module identifier.
/// </value>
public int ModuleId { get; set; }*/
/// <summary>
/// Gets or sets the end item identifier.
/// </summary>
/// <value>
/// The end item identifier.
/// </value>
[SimpleField(IsFilterable = true)]
public int EndItemId { get; set; }
/*// <summary>
/// Gets or sets the end item type identifier.
/// </summary>
/// <value>
/// The end item type identifier.
/// </value>
public int EndItemTypeId { get; set; }
/// <summary>
/// Gets or sets the name of the file.
/// </summary>
/// <value>
/// The name of the file.
/// </value>
public string FileName { get; set; }
/// <summary>
/// Gets or sets the file extension.
/// </summary>
/// <value>
/// The file extension.
/// </value>
public string FileExtension { get; set; }
/// <summary>
/// Gets or sets the name of the module type.
/// </summary>
/// <value>
/// The name of the module type.
/// </value>
public string ModuleTypeName { get; set; }
/// <summary>
/// Gets or sets the size of the file.
/// </summary>
/// <value>
/// The size of the file.
/// </value>
public long FileSize { get; set; }*/
}
Here is a picture of my azure search settings on portal.azure for my index:
Here is the code I'm calling to obtain the results:
/// <summary>
/// Gets the files azure BLOB results from azure search.
/// </summary>
/// <param name="moduleId">The module identifier.</param>
/// <param name="endItemId">The end item identifier.</param>
/// <param name="endItemTypeId">The end item type identifier.</param>
/// <returns></returns>
public IEnumerable<FileManagerFileSystemItem> GetFilesAzureBlobResultsFromAzureSearch(int moduleId, int endItemId, int endItemTypeId)
{
SearchOptions options = new SearchOptions()
{
Filter = string.Format("endItemId eq '82'", endItemId),
/*Filter = string.Format("moduleId eq {0} and endItemId eq {1} and endItemTypeId eq {2}", moduleId.ToString(), endItemId.ToString(), endItemTypeId.ToString()),*/
};
SearchResults<AzureSearchReturnModel> results;
SearchClient searchClient = AzureKeyVaultUtilities.CreateSearchClientForQueries();
options.Select.Add("endItemId");
/*options.Select.Add("moduleId");
options.Select.Add("endItemId");
options.Select.Add("endItemTypeId");
options.Select.Add("moduleType");
options.Select.Add("fileName");
options.Select.Add("fileExtension");
options.Select.Add("metadata_storage_size");*/
results = searchClient.Search<AzureSearchReturnModel>("*", options);
return Enumerable.Empty<FileManagerFileSystemItem>();
}
The code runs without any issues, but my data is not binding to my model.
What am I doing wrong?
It appears the count is right? When I run the query via portal.azure.us it shows me 4 results:

Based on the info you provided, I created an index and write a demo for you.This is my index:
And my code below:
First I upload some docs and then query them with binding to a specific model as you want :
using System;
using Microsoft.Azure.Search;
using Microsoft.Azure.Search.Models;
namespace AzureSearchTest
{
class Program
{
static void Main(string[] args)
{
var searchServiceName = "";
var cred = "";
var indexName = "";
SearchServiceClient serviceClient = new SearchServiceClient(searchServiceName, new SearchCredentials(cred));
ISearchIndexClient indexClient = serviceClient.Indexes.GetClient(indexName);
//UploadDocuments(indexClient);
var results = indexClient.Documents.Search<AzureSearchReturnModel>("*");
Console.WriteLine(results.Results.Count);
}
private static void UploadDocuments(ISearchIndexClient indexClient) {
var AzureSearchReturnModels = new AzureSearchReturnModel[] {
new AzureSearchReturnModel(){
ModuleId = "1" ,
EndItemId = "100",
EndItemTypeId = "200",
FileName= "test file 1",
FileExtension ="txt",
ModuleTypeName = "demo",
FileSize = 20000
},
new AzureSearchReturnModel(){
ModuleId = "2" ,
EndItemId = "100",
EndItemTypeId = "200",
FileName= "test file 2",
FileExtension ="aaa",
ModuleTypeName = "demo",
FileSize = 50000
},
new AzureSearchReturnModel(){
ModuleId = "3" ,
EndItemId = "100",
EndItemTypeId = "200",
FileName= "test file 3",
FileExtension ="bbb",
ModuleTypeName = "demo",
FileSize = 60000
}
};
var batch = IndexBatch.Upload(AzureSearchReturnModels);
indexClient.Documents.Index(batch);
}
}
public class AzureSearchReturnModel
{
[Newtonsoft.Json.JsonProperty(PropertyName = "moduleId")]
public String ModuleId { get; set; }
[Newtonsoft.Json.JsonProperty(PropertyName = "endItemId")]
public String EndItemId { get; set; }
[Newtonsoft.Json.JsonProperty(PropertyName = "endItemTypeId")]
public String EndItemTypeId { get; set; }
[Newtonsoft.Json.JsonProperty(PropertyName = "fileName")]
public string FileName { get; set; }
[Newtonsoft.Json.JsonProperty(PropertyName = "fileExtension")]
public string FileExtension { get; set; }
[Newtonsoft.Json.JsonProperty(PropertyName = "moduleType")]
public string ModuleTypeName { get; set; }
[Newtonsoft.Json.JsonProperty(PropertyName = "metadata_storage_size")]
public long FileSize { get; set; }
}
}
Result:

Related

C# - After executing the remove statement , list stays the same

Everyone , I tried to remove item based on condition but it seems that after executing the remove statement my list stays the same .
class Menu
public class Menu : Entity
{
/// <summary>
/// Tạo mới guid khi gọi tới menu
/// </summary>
public Menu()
{
Random rnd = new Random();
Id = rnd.Next(1,999999) * DateTime.Now.Millisecond;
Guid = Guid.NewGuid();
}
/// <summary>
/// Danh sách Role
/// </summary>
[Required(ErrorMessage = nameof(EnumManageMenu.ENM01))]
public ICollection<string> Roles { get; set; }
/// <summary>
/// Danh sách Permisions
/// </summary>
[Required(ErrorMessage = nameof(EnumManageMenu.ENM02))]
public ICollection<string> Permisions { get; set; }
/// <summary>
/// Tên của từng menu
/// </summary>
[Required(ErrorMessage = nameof(EnumManageMenu.ENM03))]
[MaxLength(200, ErrorMessage = nameof(EnumManageMenu.ENM07))]
public string Name { get; set; }
/// <summary>
/// Đường dẫn
/// </summary>
[Required(ErrorMessage = nameof(EnumManageMenu.ENM09))]
[MaxLength(1000, ErrorMessage = nameof(EnumManageMenu.ENM08))]
public string Link { get; set; }
/// <summary>
/// Mỗi menu sẽ chứa một loại menu
/// </summary>
public ICollection<Menu> Items { get; set; }
/// <summary>
/// Mô tả thêm của từng menu
/// </summary>
[MaxLength(2000, ErrorMessage = nameof(EnumManageMenu.ENM11))]
public string Description { get; set; }
/// <summary>
/// Loại menu
/// </summary>
[Required(ErrorMessage = nameof(EnumManageMenu.ENM03))]
[MaxLength(1000, ErrorMessage = nameof(EnumManageMenu.ENM013))]
public string EnumCode { get; set; }
/// <summary>
/// Icon của menu
/// </summary>
[Required(ErrorMessage = nameof(EnumManageMenu.ENM016))]
[MaxLength(1000, ErrorMessage = nameof(EnumManageMenu.ENM017))]
public string Icon { get; set; }
/// <summary>
/// Trạng thái của menu
/// </summary>
public bool Active { get; set; }
/// <summary>
/// Sắp xếp danh sách menu
/// </summary>
public int SortOrder { get; set; }
}
below is my code
public async Task<MethodResult<List<MenuModel>>> GetAllMenuAsync()
{
MethodResult<List<MenuModel>> methodResult = new MethodResult<List<MenuModel>>();
List<Menu> empty = new List<Menu>();
List<Menu> menus = await _dbCollection.Find(FilterDefinition<Menu>.Empty).ToListAsync();
empty = menus;
int countList = menus.Count;
for (int i = 0; i < countList; i++)
{
foreach (var item in GetListNoDel(menus[i]))
{
if (item.IsDeleted)
{
empty.Remove(item);
}
}
}
List<MenuModel> menuModels = _mapper.Map<List<MenuModel>>(empty);
methodResult.Result = menuModels;
return methodResult;
}
private IEnumerable<Menu> GetListNoDel(Menu menus)
{
yield return menus;
foreach (var item in menus.Items)
{
foreach (var items in GetListNoDel(item))
{
yield return items;
}
}
}
You cannot "foreach" over a list and immediately remove items (as you undoubtedly know). So you will have to first find the items to remove, and then remove them. A twist in your case is that those "items to remove" can be at any depth in a menu tree.
So when you find an item to remove, also remember which list it appears in. Then you can directly remove it from that list.
void MainMethod()
{
var menulist = new List<Menu>(); // omitted: fill list
// get the *full* list of items to remove,
// so you don't change a list that is still used in a foreach
var todelete = ToDelete(menulist).ToList();
// and remove them from their parent list
foreach (var todo in todelete)
{
todo.list.Remove(todo.child);
}
}
private IEnumerable<(List<Menu> list, Menu child)> ToDelete(List<Menu> menuitems)
{
foreach (var item in menuitems)
{
if (item.IsDeleted)
{
// now we know that "item" must be removed from "menuitems"
yield return (menuitems, item);
}
else
{
// if the parent is deleted, then all children will be gone as well
// - so only recursively check non-deleted items
// pass the results of a recursive call up the call stack
foreach (var pairs in ToDelete(item.Items))
{
yield return pairs;
}
}
}
}

ASP.NET Core JSON param always null

I am trying to pass a serialized model from ajax to my controller, but I can't seem to get anything but null to come across. Rather than spend a lot of time talking, I am just going to show code.
The queryDetails is properly formatting the object into { name: val } format, but it is not coming across into the controller.
Summary.cshtml Javascript Code
top of file declaration:
var QueryData = ViewData["QueryData"] as QueryModel;
....
in Js code:
var queryDetails = #Html.Raw(Json.Serialize(#QueryData));
$.ajax({
type: 'POST',
url: '/Home/SummaryRefresh',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: { queryDetails },
success: function () {
},
error: function (error) {
alert(error);
}
});
HomeController.cs
[HttpPost]
public IActionResult SummaryRefresh([FromBody] QueryModel queryDetails)
{
// STACKOVERFLOW NOTE: function is hit, but queryDetails is null
if (queryDetails != null)
{
ViewData["QueryData"] = queryDetails;
return View("Summary");
}
else
return BadRequest("Error refreshing view");
}
Startup.cs
...
endpoints.MapControllerRoute(
name: "SummaryRefresh",
pattern: "{controller=Home}/{action=SummaryRefresh}/{queryDetails?}");
...
QueryModel.cs
/// <summary>
/// Holds the query data enetered by user
/// </summary>
public class QueryModel
{
/// <summary>
/// Different ways to view summary mode
/// </summary>
public enum SummaryDisplayMode
{
Full,
Quick
}
/// <summary>
/// Current summary view mode
/// </summary>
private SummaryDisplayMode displayMode = SummaryDisplayMode.Full;
/// <summary>
/// Get/Set display mode
/// </summary>
public SummaryDisplayMode DisplayMode { get => displayMode; set => displayMode = value; }
/// <summary>
/// PO Name filter
/// </summary>
[Display(Name = "Product Owner", Prompt = "Name")]
public string POName { get; set; }
/// <summary>
/// Delivery Order Filter
/// </summary>
[Display(Name = "Delivery Order", Prompt = "Example: [removed]")]
public string DeliveryOrder { get; set; }
/// <summary>
/// Port Number filter
/// </summary>
[RegularExpression(#"^PORT-+([0-9]{3}|[0-9]{4}|[0-9]{5})$", ErrorMessage = "[removed]")]
[Display(Name = "[removed]")]
public string PortNumber { get; set; }
/// <summary>
/// Epic Type filter
/// </summary>
[Display(Name = "Epic Type")]
public string EpicType { get; set; }
/// <summary>
/// Program Increment Filter
/// </summary>
[Display(Name = "Program Increment", Prompt = "Example: 20D")]
public string ProgramIncrement { get; set; }
/// <summary>
/// Whether or not to show resolved capabilities
/// </summary>
[Display(Name = "Show Resolved Ports")]
public bool ShowResolved { get; set; }
/// <summary>
/// Whether or not to show backlogs
/// </summary>
[Display(Name = "Show Backlogs")]
public bool ShowBacklogs { get; set; }
/// <summary>
/// Constructor
/// </summary>
public QueryModel()
{
POName = "";
PortNumber = "";
DeliveryOrder = "";
EpicType = "NA";
ShowResolved = true;
ShowBacklogs = false;
}
}
Debugged paylod:
displayMode=0&poName=jkeller&deliveryOrder=&portNumber=&epicType=NA&programIncrement=&showResolved=true&showBacklogs=false
Solution seems to be to replace
data: { queryDetails },
with
data: JSON.stringify(queryDetails),
Reason is that this line creates an object, not JSON
var queryDetails = #Html.Raw(Json.Serialize(#QueryData));
Hence the object needs to be converted to JSON before performing the POST.
This was tested in Visual Studio, and it is working
[Route("~/Home/SummaryRefresh")]
public IActionResult SummaryRefresh( QueryModel queryDetails)
ajax should be like this
var queryDetails = #Html.Raw(Json.Serialize(#QueryData));
$.ajax({
type: 'POST',
url: '/Home/SummaryRefresh',
data: { queryDetails:queryDetails },
success: function (result) {
},
error: function (error) {
alert(error);
}
});

Array types with <example> tag not working with Swagger (swashbuckle.aspnetcore)

I am using the summary and example tags for the swagger documentation.
I have a problem with the tag, it's not recognized by swagger when I use array :
I use swashbuckle.aspnetcore package Nuget.
Example :
[DataContract]
public class HeaderResponse
{
/// <summary>
/// Statut code
/// </summary>
///<example>400</example>
[DataMember]
public int StatusCode { get; set; }
/// <summary>
/// Title
/// </summary>
/// <example>Erreur sur methode1</example>
[DataMember]
public string Title { get; set; }
/// <summary>
/// List of errors
/// </summary>
///<example>["entry1", "entry2", "entry3"]</example>
[DataMember]
public List<string> ErrorList { get; } = new List<string>();
}
On swagger documentation, array is not interpreted :
I found others solutions by using ISchemaFilter like this :
public class SwaggerExcludeFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
switch (context.Type.Name)
{
case "HeaderResponse":
foreach (var property in schema.Properties)
{
if (property.Value.Type == "array")
{
var array = new OpenApiArray();
array.Add(new OpenApiString("item1"));
array.Add(new OpenApiString("item2"));
array.Add(new OpenApiString("item3"));
property.Value.Example = array;
}
}
break;
}
}
}
Is there no other way than to use ISchemaFilter to handle tags of type array?
You can try to do like this:
public List<string> ErrorList { get; } = new List<string>{"entry1", "entry2", "entry3"};
or:
[DataContract]
public class HeaderResponse
{
public HeaderResponse()
{
ErrorList = new List<string> {"entry1", "entry2", "entry3" };
}
/// <summary>
/// Statut code
/// </summary>
///<example>400</example>
[DataMember]
public int StatusCode { get; set; }
/// <summary>
/// Title
/// </summary>
/// <example>Erreur sur methode1</example>
[DataMember]
public string Title { get; set; }
/// <summary>
/// List of errors
/// </summary>
[DataMember]
public List<string> ErrorList { get; set; }
}
Here is a demo:
[HttpPost("TestPar")]
public IActionResult TestPar(HeaderResponse h)
{
return Json(h);
}
result:
The quotes must be escaped using "
/// <summary>
/// List of errors
/// </summary>
///<example>["entry1","entry2","entry3"]</example>
[DataMember]
public List<string> ErrorList { get; } = new List<string>();
I have the same problem and I try this. you can add a condition on the name of the property and add the null return in order not to lose the example on the other properties. But the best solution would be to be able to find a generic solution. How is it possible to get the example tag and the property name with ISchemaFilter ? This is my solution :
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
schema.Example = GetExampleOrNullFor(schema, context);
}
private IOpenApiAny GetExampleOrNullFor(OpenApiSchema schema, SchemaFilterContext context)
{
switch (context.Type.Name)
{
case "MyClass":
foreach (var property in schema.Properties)
{
//Array property, which wraps its elements
if (property.Value.Type == "array")
{
if (property.Key == "MyProperty1")
{
var array = new OpenApiArray();
array.Add(new OpenApiString("item1"));
array.Add(new OpenApiString("item2"));
property.Value.Example = array;
}
else if (property.Key == "MyProperty2")
{
var array = new OpenApiArray();
array.Add(new OpenApiString("item1"));
property.Value.Example = array;
}
}
}
return null;
default:
return null;
}
}
Support for examples using XML comments on arrays was added in Swashbuckle.AspNetCore version 6.0.0.
It's mentioned in this GitHub issue and their documentation shows the following example:
/// <summary>
/// The sizes the product is available in
/// </summary>
/// <example>["Small", "Medium", "Large"]</example>
public List<string> Sizes { get; set; }

How to read Xml to Linq from service

I have a string data get from service Location Xml
I want to read response text and return ObservableCollection
public void SearchLocation(string address)
{
var webclient = new WebClient();
if (address != "")
{
string url =
string.Format(
#"http://dev.virtualearth.net/REST/v1/Locations?countryRegion=Vietnam&adminDistrict=Ha Noi&locality={0}&o=xml&key={1}",
address, BingMapKey);
webclient.DownloadStringAsync(new Uri(url));
webclient.DownloadStringCompleted += WebclientOnDownloadStringCompleted;
}
}
private void WebclientOnDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
string data = e.Result;
ReadXml(data);
}
private void ReadXml(string data)
{
_locations.Clear();
XDocument document = XDocument.Parse(data);
var locations = from loca in document.Descendants("Location")
select
new Location(loca.Element("Name").Value,
loca.Element("Point").Element("Latitude").Value,"1",
"1", "1", "1", "1");
_locations = (ObservableCollection<Location>) locations;
}
}
Class Location:
public class Location
{
/// <summary>
/// Tên địa điểm
/// </summary>
public string Name { get; set; }
/// <summary>
/// Vĩ độ
/// </summary>
public double Latitude { get; set; }
/// <summary>
/// Kinh độ
/// </summary>
public double Longitute { get; set; }
/// <summary>
/// Vĩ độ Nam
/// </summary>
public double SouthLatitude { get; set; }
/// <summary>
/// Kinh độ Tây
/// </summary>
public double WestLongtitue { get; set; }
/// <summary>
/// Vĩ độ Bắc
/// </summary>
public double NorthLatitude { get; set; }
/// <summary>
/// Kinh độ Tây
/// </summary>
public double EastLongitude { get; set; }
/// <summary>
/// Khởi tạo Location
/// </summary>
/// <param name="name">tên địa điểm</param>
/// <param name="latitue">vĩ độ</param>
/// <param name="longitude">kinh độ</param>
/// <param name="southLatitude">vĩ độ nam</param>
/// <param name="westLongitude">kinh độ tây</param>
/// <param name="northLatitude">vĩ độ bắc</param>
/// <param name="eastLongitude">kinh độ đông</param>
public Location(string name, string latitue, string longitude, string southLatitude, string westLongitude,
string northLatitude, string eastLongitude)
{
Name = name;
Latitude = Convert.ToDouble(latitue);
Longitute = Convert.ToDouble(longitude);
SouthLatitude = Convert.ToDouble(southLatitude);
NorthLatitude = Convert.ToDouble(northLatitude);
WestLongtitue = Convert.ToDouble(westLongitude);
EastLongitude = Convert.ToDouble(eastLongitude);
}
}
I read and _location return null, where are errors?
You can cast IEnumerable<Location> which is a result of LINQ to XML query to ObservableCollection<Location> directly.
_locations = (ObservableCollection<Location>) locations;
Just add all elements from query result collection into existing ObservableCollection:
foreach(var location in locations)
_locations.Add(location);
Update
There is also namespace problem in your code. Try that one:
XDocument document = XDocument.Parse(data);
var ns = XNamespace.Get("http://schemas.microsoft.com/search/local/ws/rest/v1");
var locations = from loca in document.Descendants(ns + "Location")
select
new Location(loca.Element(ns + "Name").Value,
loca.Element(ns + "Point").Element(ns + "Latitude").Value, "1",
"1", "1", "1", "1");

C# XML Serializable Error

i am trying to XML serialize a class object but having the following problem:
the code compiles fine and the messagebox displays all the correct data but when i view the XML it does not seem to include the data for the actual transfer i.e. FireGridLocation data is missing from the XML.
XmlSerializer s;
StringWriter w;
FireGridUnit fireGridUnit = new FireGridUnit();
fireGridUnit.FireGridLocation = new GridUnit(GridLock.getColumn, GridLock.getRow);
MessageBox.Show("gridlock col " + GridLock.getColumn);
MessageBox.Show("column fire " + fireGridUnit.FireGridLocation.getColumn);
MessageBox.Show("row fire " + fireGridUnit.FireGridLocation.getRow);
s = new XmlSerializer(typeof(FireGridUnit));
w = new StringWriter();
s.Serialize(w, fireGridUnit);
MessageBox.Show(w.ToString());
alt text http://img52.imageshack.us/img52/220/errorce.jpg
here is the FireGridUnit:
[Serializable]
public class FireGridUnit
{
/// <summary>
/// Location storage
/// </summary>
//public GridUnit FireGridLocation { get; set; }
public GridUnit FireGridLocation;
}
and here is the GridUnit class:
public class GridUnit
{
/// <summary>
/// Default initialization
/// </summary>
public GridUnit()
{
Column = -1;
Row = -1;
}
/// <summary>
/// Initialize to supplied coordinate
/// </summary>
/// <param name="column"></param>
/// <param name="row"></param>
public GridUnit(int column, int row)
{
Column = column;
Row = row;
}
/// <summary>
/// Set/Return Column
/// </summary>
//public int Column { get; set; }
private int Column;
public int getColumn
{
get { return Column; }
}
/// <summary>
/// Set/Return Row
/// </summary>
//public int Row { get; set; }
private int Row;
public int getRow
{
get { return Row; }
}
}
if you can assist with this issue, your input is very welcome.
XML serialization can only serialize read/write properties. Your getColumn and getRow properties are read-only, so they can't be serialized.
BTW, the Serializable attribute is not necessary for XML serialization

Categories

Resources