Add a mapping to an existing index template (using NEST attributes) - c#

In my ElasticSearch server, I have an existing index template, which contains some settings and some mappings.
I want to add a mapping for a new type to the template, but since it's not possible to update templates, I need to delete the existing one and recreate it.
Since I would like to keep all the existing settings, I tried getting the existing definition, add the mapping to it and then delete/recreate, like in this example:
using Nest;
using System;
public class SomeNewType {
[ElasticProperty(Index = FieldIndexOption.NotAnalyzed)]
public string SomeField { get; set; }
[ElasticProperty(Index = FieldIndexOption.Analyzed)]
public string AnotherField { get; set; }
}
class Program {
static void Main(string[] args) {
var settings = new ConnectionSettings(uri: new Uri("http://localhost:9200/"));
var client = new ElasticClient(settings);
var templateResponse = client.GetTemplate("sometemplate");
var template = templateResponse.TemplateMapping;
client.DeleteTemplate("sometemplate");
// Add a mapping to the template somehow...
template.Mappings.Add( ... );
var putTemplateRequest = new PutTemplateRequest("sometemplate") {
TemplateMapping = template
};
client.PutTemplate(putTemplateRequest);
}
}
However, I cannot find a way to add a mapping to the template definition using the ElasticProperty attributes, like in
client.Map<SomeNewType>(m => m.MapFromAttributes());
Is it possible to create a RootObjectMapping to add to the Mappings collection with something similar to MapFromAttributes?

You can do this by using the more robust PutMappingDescriptor to get a new RootObjectMapping, then add that into the collection returned by your GET _template request, like so:
var settings = new ConnectionSettings(uri: new Uri("http://localhost:9200/"));
var client = new ElasticClient(settings);
var templateResponse = client.GetTemplate("sometemplate");
var template = templateResponse.TemplateMapping;
// Don't delete, this way other settings will stay intact and the PUT will override ONLY the mappings.
// client.DeleteTemplate("sometemplate");
// Add a mapping to the template like this...
PutMappingDescriptor<SomeNewType> mapper = new PutMappingDescriptor<SomeNewType>(settings);
mapper.MapFromAttributes();
RootObjectMapping newmap = ((IPutMappingRequest) mapper).Mapping;
TypeNameResolver r = new TypeNameResolver(settings);
string mappingName = r.GetTypeNameFor(typeof(SomeNewType));
template.Mappings.Add(mappingName, newmap);
var putTemplateRequest = new PutTemplateRequest("sometemplate")
{
TemplateMapping = template
};
var result = client.PutTemplate(putTemplateRequest);
Note: TypeNameResolver is in the Nest.Resolvers namespace
As noted in the comment above, I recommend that you NOT delete the old template if the mappings are the only thing that needs updated, otherwise you will need to copy all of the other relevant settings into your new request.

Related

Fill combobox with XML data

I want to get data from a XML file (https://xml.buienradar.nl/) and fill a combobox with that data. I want each regio from <weerstation regio=>
to be shown in the combobox.
I could not find anything working for me in UWP
Easiest way is to use XElement to load XML and then query over it.
First you need ComboBox in XAML page:
<ComboBox x:Name="Stations" />
Add new event handler for Loaded event and in code behind use this code to load XML and fill ComboBox:
private void MainPage_OnLoaded(object sender, RoutedEventArgs e)
{
var requestUri = new Uri("https://xml.buienradar.nl/");
var httpClient = new HttpClient();
var httpResponse = await httpClient.GetAsync(requestUri);
httpResponse.EnsureSuccessStatusCode();
var httpResponseStream = await httpResponse.Content.ReadAsStreamAsync();
var root = XElement.Load(httpResponseStream);
var stations =
from element in root.Descendants("weerstation")
select element;
foreach (var station in stations)
{
Stations.Items?.Add(station.Attribute("id")?.Value);
}
}
Here is link to source where I get idea.
And also link where you'll find documentation how to do simple HTTP GET request.
You could use LinqToXML to read the data and then set that as the ItemSource.
You can start of with the following snippet (see in action here):
var xml = XDocument.Load("https://xml.buienradar.nl/");
var weerstationList = xml.Descendants("weerstation");
var weerstations = weerstationList.Select(w => new Item()
{
Id = w.Attribute("id").Value,
Name = w.Descendants("stationnaam").First().Value
});
and the following helper class:
public class Item
{
public string Id { get; set; }
public string Name { get; set; }
}
You can then set the list of items weerstations as your ItemSource of the combo-box.

Using VsConnection WorkItemTrackingHttpClient patch to add parent relation via VSTS client API

I am trying to programmatically add a parent-child relationship between two work items. I am using the Microsoft Team Foundation and Visual Studio Services libraries to export and import TFS 2015 and VSTS backlog objects.
https://learn.microsoft.com/en-us/vsts/integrate/concepts/dotnet-client-libraries
https://www.visualstudio.com/en-us/docs/integrate/api/wit/samples#migrating-work-items
I have worked through obtaining a VssConnection to my servers and getting a WorkItemTrackingHttpClient to execute Wiql queries and create work items. I also have a query to identify the parent of a target work item.
What I cannot figure out is how to add the link between child work items and their parent. I do not know the correct JsonPatchDocument item path to add the parent, or the correct property or method on an existing WorkItem to update it with a parent link. Does anyone have documentation links or specific information on adding a parent relationship to a work item using these libraries?
Here are some code excerpts for context:
using Microsoft.TeamFoundation.Core.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.Client;
using Microsoft.VisualStudio.Services.WebApi;
using Microsoft.VisualStudio.Services.WebApi.Patch;
using Microsoft.VisualStudio.Services.WebApi.Patch.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
// ...
var sourceConnection = new VssConnection(new Uri(_sourceTsUrl), new VssClientCredentials());
var targetConnection = new VssConnection(new Uri(_targetTsUrl), new VssClientCredentials());
var sourceClient = sourceConnection.GetClient<WorkItemTrackingHttpClient>();
var targetClient = targetConnection.GetClient<WorkItemTrackingHttpClient>();
// ...
var queryResults = sourceClient.QueryByWiqlAsync(query).Result;
var ids = queryResults.WorkItems.Select(x => x.Id).ToList();
var items = sourceClient.GetWorkItemsAsync(ids);
foreach (var item in items.Result)
{
// ...
var patchItem = new JsonPatchDocument();
foreach (var fieldName in item.Fields.Keys)
{ patchItem.Add(new JsonPatchOperation() { Path = $"/fields/{fieldName}", Value = item.Fields[fieldName], Operation = Operation.Add }); }
// TODO - add patch field(?) for parent relationship
var parentResults = sourceClient.QueryByWiqlAsync(parentQuery).Result;
// ...
var task = targetClient.CreateWorkItemAsync(patchItem, targetProject, itemType, validateOnly, bypassRules, suppressNotifications);
var newItem = task.Result;
// TODO - alternatively, add parent via the returned newly generated WorkItem
}
Addendum:
I've tried adding the following code, but the changes do not get committed to the remote object, it only exists in local memory, and I cannot find a method to push the changes/updates.
if (!string.IsNullOrWhiteSpace(mappedParentUrl))
{
if (newItem.Relations == null)
{ newItem.Relations = new List<WorkItemRelation>(); }
newItem.Relations.Add(new WorkItemRelation() { Rel = "Parent", Title = mappedParentTitle, Url = mappedParentUrl });
}
Refer to this code to create task work item with parent link (Update it to meet your requirement):
var url = new Uri("https://XXX.visualstudio.com");
var connection = new VssConnection(url, new VssClientCredentials());
var workitemClient = connection.GetClient<WorkItemTrackingHttpClient>();
string projectName = "[project name]";
int parentWITId = 771;//parent work item id
var patchDocument = new Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchDocument();
patchDocument.Add(new Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchOperation() {
Operation=Operation.Add,
Path= "/fields/System.Title",
Value="parentandchildWIT"
});
patchDocument.Add(new Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchOperation()
{
Operation = Operation.Add,
Path = "/relations/-",
Value = new
{
rel = "System.LinkTypes.Hierarchy-Reverse",
url = connection.Uri.AbsoluteUri+ projectName+ "/_apis/wit/workItems/"+parentWITId,
attributes = new
{
comment = "link parent WIT"
}
}
});
var createResult = workitemClient.CreateWorkItemAsync(patchDocument, projectName, "task").Result;

MFiles API setting propertyValue

I'm working with MFiles API...
I want to pass a propertyDef to a propertyValue...
This code is working... but I have to create the MFiles object first.
ObjectVersionAndProperties objVersion =
mFilesStructure.MFileVault.ObjectOperations.CreateNewObject(objTypeID,
propValues);
var testPropValues = new PropertyValues();
testPropValues = FilesStructure.MFileVault.ObjectPropertyOperations.GetProperties(objVersion.ObjVer);
var testPropValue = new PropertyValue();
testPropValue = testPropValues.SearchForProperty(typeClientID);
it work fine "testPropValue" has all the property set correctly espacially the DataType... but don't want to create the MFiles at first...
This should do the same, in my opinion but doesn't
var test = new PropertyDef();
test = mFilesStructure.MFileVault.PropertyDefOperations.GetPropertyDef(typeClientID);
var testPropValue = new PropertyValue();
testPropValue.PropertyDef = test.ID;
the properties doesn't setup correctly...
Any one can help
Best regards,
Steph
I just stumbled across this looking for something else and thought I might help.
You actually have it a little backwards. The creation of the new object is actually the last step in the process. You need to create a collection of PropertyValues() by creating each individual PropertyValue() and then adding them to the collection.
So something like this:
public static PropertyValue GetPropertyValue(int propertyDefId, object value)
{
//resolve property def by ID
PropertyDef propertyDef = Vault.PropertyDefOperations.GetPropertyDef(propertyDefId);
//create the property value with prop def ID and value
return GetPropertyValue(propertyDefId, propertyDef.DataType, value);
}
public static PropertyValue GetPropertyValue(int propertyDefId, MFDataType dataType, object value)
{
PropertyValue propertyValue = new PropertyValue();
propertyValue.PropertyDef = propertyDefId;
propertyValue.TypedValue.SetValue(dataType, value);
return propertyValue;
}
public static ObjectVersionAndProperties CreateDocument(PropertyValues propertyValues, string filepath, Vault vault)
{
// Create the Source File object from the filepath.
SourceObjectFile sourceFile = new SourceObjectFile();
sourceFile.SourceFilePath = filepath;
sourceFile.Extension = Path.GetExtension(filepath).TrimStart('.');
sourceFile.Title = Path.GetFileNameWithoutExtension(filepath).TrimEnd('.');
// Create the document object.
return vault.ObjectOperations.CreateNewSFDObject((int)MFBuiltInObjectType.MFBuiltInObjectTypeDocument,
propertyValues, sourceFile, true);
}
Once you set up the above functions you could call them like:
//If the document doesn't exist, go ahead and create a new one
//creat and add all the properties
PropertyValues props = new PropertyValues();
//class
props.Add(-1, HelperMF.GetClassPropertyValue(classId, env.Vault));
//job
int jobId = env.Vault.ValueListItemOperations.GetValueListItemByDisplayID(Structure.ObjType.Job.ID, jobDisplayId).ID;
props.Add(-1, HelperMF.GetPropertyValue(Properties.Job.ID, jobId, env.Vault));
//estimates
props.Add(-1, HelperMF.GetPropertyValueFromListOfDisplayIds(env.Vault, Properties.Estimate.ID,
MFDataType.MFDatatypeMultiSelectLookup, Structure.ObjType.Estimate.ID, estimateDisplayIds));
//Add the relationship to the return doc that was uploaded
props.Add(-1, HelperMF.GetPropertyValue(Properties.Document.ID, movingDocId, env.Vault));
//create the new object in the vault
ObjectVersionAndProperties newDoc = HelperMF.CreateDocument(props, docDownloadPath, env.Vault);
I use a lot of help functions and classes but you should get the gist from my samples. Also, I would highly recommend you use the M-Files community website for research as they have a lot of code samples there geared specifically for M-Files.
https://community.m-files.com/
Also, if you don't already, use the API documentation as it also includes code samples.
http://www.m-files.com/api/documentation/2015.2/
Hopefully this helps,
Mike

Deserialize iCal using DDay.iCal, can't find the properties

I'm trying to deserialize an iCal file and then map the collection to a custom POCO. The problem is that I'm not sure where the properties are stored.
Here's the Deserialization method
public static IICalendarCollection Deserialize(String iCalUri)
{
var wc = new WebClient();
var result = wc.DownloadString(iCalUri);
using (var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(result)))
{
var serializer = new iCalendarSerializer();
var collection = (iCalendarCollection)serializer.Deserialize(memoryStream, Encoding.UTF8);
return collection;
}
}
Then in my service, I'm trying to map the properties to my POCO, but I can't find the properties.
var url = string.Format(GoogleICalUrl, calendarID);
var feed = iCalUtility.Deserialize(url);
foreach(var e in feed)
{
calendarModel.title = e.WhereTheHellAreThePropertiesKept;
}
Does anyone know the right way to loop through the iCalendarCollection and get all the properties?
I checked the DDay website but it's been down all day.
After some digging, it turns out that IICalendarCollection has a nested Event collection that needs to be parsed as follows.
var url = string.Format(GoogleICalUrl, calendarID);
var feed = iCalUtility.Deserialize(url);
foreach (var ev in feed.SelectMany(e => e.Events))
{
calendarModel.Add(new CalendarModel {description = ev.Description,
title = ev.Summary});
}

Reach functionality from other class c#

update
I'm writing a silverlight application and I have the following Class "Home", in this class a read a .xml file a write these to a ListBox. In a other class Overview I will show the same .xml file. I know it is stupid to write the same code as in the class "Home".
The problem is, how to reach these data.
My question is how can I reuse the method LoadXMLFile() from another class?
The code.
// Read the .xml file in the class "Home"
public void LoadXMLFile()
{
WebClient xmlClient = new WebClient();
xmlClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(XMLFileLoaded);
xmlClient.DownloadStringAsync(new Uri("codeFragments.xml", UriKind.RelativeOrAbsolute));
}
private void XMLFileLoaded(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
string xmlData = e.Result;
XDocument xDoc = XDocument.Parse(xmlData);
var tagsXml = from c in xDoc.Descendants("Tag") select c.Attribute("name");
List<Tag> lsTags = new List<Tag>();
foreach (string tagName in tagsXml)
{
Tag oTag = new Tag();
oTag.name = tagName;
var tags = from d in xDoc.Descendants("Tag")
where d.Attribute("name").Value == tagName
select d.Elements("oFragments");
var tagXml = tags.ToArray()[0];
foreach (var tag in tagXml)
{
CodeFragments oFragments = new CodeFragments();
oFragments.tagURL = tag.Attribute("tagURL").Value;
//Tags.tags.Add(oFragments);
oTag.lsTags.Add(oFragments);
}
lsTags.Add(oTag);
}
//List<string> test = new List<string> { "a","b","c" };
lsBox.ItemsSource = lsTags;
}
}
Create a class to read the XML file, make references to this from your other classes in order to use it. Say you call it XmlFileLoader, you would use it like this in the other classes:
var xfl = new XmlFileLoader();
var data = xfl.LoadXMLFile();
If I were you, I would make the LoadXMLFile function take a Uri parameter to make it more reusable:
var data = xfl.LoadXMLFile(uriToDownload);
You could create a class whose single responsibility is loading XML and returning it, leaving the class that calls your LoadXmlFile method to determine how to handle the resulting XML.

Categories

Resources