I've got an XSD to validate a XML-file before importing it into an other program. It worked already for 1 week. But yesterday the validation failed an I don't know why.
The error occurs at the validation of the email-adress. This is the validation of the email-adress in the XSD-file:
<simpleType name="EMailAdressType">
<annotation>
<documentation></documentation>
</annotation>
<restriction base="string">
<pattern value="\w+([-+.']\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*">
</pattern>
<minLength value="0"></minLength>
<maxLength value="64"></maxLength>
<pattern value="\s*"></pattern>
</restriction>
</simpleType>
And this is my C#-methode to validate a XML-file against a XSD-file:
public static List<string> ValidateXMLAgainstXSD(string xmlPath, string xsdPath, string targetNamespace)
{
/// Rückgabeliste für die Validierungsfehler
List<string> validationErrors = new List<string>();
/// Klasse für die XML-Schemas (XSD-Dateien)
XmlSchemaSet schemas = new XmlSchemaSet();
/// Neues XML-Schema hinzufügen
schemas.Add(targetNamespace, xsdPath);
/// Das XML-Dokument, das validiert werden soll
XDocument custOrdDoc = XDocument.Load(xmlPath);
/// Validierungs-Vorgang
custOrdDoc.Validate(schemas, (o, e) =>
{
validationErrors.Add(e.Message);
});
/// Validierungsfehlerliste zurück geben
return validationErrors;
}
The error-message is (translated by myself from german to english):
This element 'EMailAdress' is not valid - The value
'mayer_johann75#web.de' is because of his datatype
'http://www.abcde.de/mhr/applicants/:EMailAdressType' not valid --
Pattern-restriction failed..
When I take the Pattern from the XSD-file and try the validation from the email-adress-string directly with the Regex-Class then it is valid...
What is wrong?
As pointed out by the earlier comments, .Net interprets \w differently to w3c. For .Net its equivalent to [a-zA-Z0-9_] whereas for XSD schemas, the \w option doesn't include the underscore. Just replace all those \w with [A-Za-z0-9_] and everything should be fine.
Related
This question already has answers here:
Get text between 2 html tags c#
(3 answers)
Closed 3 years ago.
I have some data in a file and I am using Regex to get individual elements and remove all the \r\n between the <opening> and </closing> tags.
But when i am trying to select the elements separately, at the end, the whole data is getting selected as one group.
This is my Regex:
(<([ph0-9figc]+)>)([a-zA-Z0-9äöüÄÖÜß[:punct:] \n\r\t])+(<\/\2>)
Sample with Input Data
It may not be the best idea to do this task with regular expressions, especially for replacing new lines.
If we really have to, we might want to capture those tags one by one. For instance, this expression only captures the p tags using three capturing groups ():
(<p>)([\s\S]*?)(<\/p>)
regex101.com.
RegEx Circuit
We can also visualize your expressions in jex.im:
JavaScript Demo
const regex = /(<p>)([\s\S]*?)(<\/p>)/gm;
const str = `<p>
<st>Liebe stern-Redaktion,
</st>
<i>Liebe stern-Redaktion,</i> warum schreiben Sie nicht, was wirklich freitags whrend der Protest-Demos am Grenzzaun passiert? Wie die Familien der Mrder fr jede gettete jdische Person belohnt werden? Oder ber die Feuerballons, die aus dem Gazastreifen in den Sden Israels geschickt werden? Brita Singh, Scheeel</p>
<fig>
<img src="images/img_8-1.jpg" width="596" height="428" alt="" />
<fc>
<i>stern</i> Nr. 10/2019, Bild der Woche: Kindertrauer im Gazastreifen</fc>
</fig>
<p>
<i>Sehr geehrte Frau Singh,</i> bei Demonstrationen am Grenzzaun starben laut Bericht der UN-Kommission in neun Monaten 35 Kinder durch Schüsse israelischer Soldaten. Zwei Journalisten und drei Sanitäter wurden erschossen, über 6000 Menschen verletzt. Israel hat gerade Ermittlungen zu elf der Todesfälle aufgenommen. Dagegen hat es in dem Zeitraum kein israelisches Todesopfer am Grenzzaun zu Gaza gegeben. Die Hamas pflegt einen Märtyrerkult und belohnt Morde mit Geld; israelische Sicherheitskräfte zerstören Häuser von Angehörigen palästinensischer Attentäter. Beides fördert den Hass. Opfer sind Menschen wie das Mädchen auf diesem Bild. Der <i>stern</i> hat keinen einseitigen Blick auf die Komplexität des Nahostkonflikts wir schauen stets auf beide Seiten. <i>Mit freundlichen Grüßen Cornelia Fuchs, Ressortleiterin Ausland</i></p>
<p>Eine liebevolle Mutter will, dass ihr Kind glücklich ist, egal, ob sie sein Leben versteht. Alles andere ist Egoismus und keine Mutterliebe. </p>
<p>Annemarie Fischer, Wielenbach</p>`;
let m;
while ((m = regex.exec(str)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
// The result can be accessed through the `m`-variable.
m.forEach((match, groupIndex) => {
console.log(`Found match, group ${groupIndex}: ${match}`);
});
}
C# Test
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main()
{
string pattern = #"(<p>)([\s\S]*?)(<\/p>)";
string input = #"<p>
<st>Liebe stern-Redaktion,
</st>
<i>Liebe stern-Redaktion,</i> warum schreiben Sie nicht, was wirklich freitags whrend der Protest-Demos am Grenzzaun passiert? Wie die Familien der Mrder fr jede gettete jdische Person belohnt werden? Oder ber die Feuerballons, die aus dem Gazastreifen in den Sden Israels geschickt werden? Brita Singh, Scheeel</p>
<fig>
<img src=""images/img_8-1.jpg"" width=""596"" height=""428"" alt="""" />
<fc>
<i>stern</i> Nr. 10/2019, Bild der Woche: Kindertrauer im Gazastreifen</fc>
</fig>
<p>
<i>Sehr geehrte Frau Singh,</i> bei Demonstrationen am Grenzzaun starben laut Bericht der UN-Kommission in neun Monaten 35 Kinder durch Schüsse israelischer Soldaten. Zwei Journalisten und drei Sanitäter wurden erschossen, über 6000 Menschen verletzt. Israel hat gerade Ermittlungen zu elf der Todesfälle aufgenommen. Dagegen hat es in dem Zeitraum kein israelisches Todesopfer am Grenzzaun zu Gaza gegeben. Die Hamas pflegt einen Märtyrerkult und belohnt Morde mit Geld; israelische Sicherheitskräfte zerstören Häuser von Angehörigen palästinensischer Attentäter. Beides fördert den Hass. Opfer sind Menschen wie das Mädchen auf diesem Bild. Der <i>stern</i> hat keinen einseitigen Blick auf die Komplexität des Nahostkonflikts wir schauen stets auf beide Seiten. <i>Mit freundlichen Grüßen Cornelia Fuchs, Ressortleiterin Ausland</i></p>
<p>Eine liebevolle Mutter will, dass ihr Kind glücklich ist, egal, ob sie sein Leben versteht. Alles andere ist Egoismus und keine Mutterliebe. </p>
<p>Annemarie Fischer, Wielenbach</p>";
RegexOptions options = RegexOptions.Multiline;
foreach (Match m in Regex.Matches(input, pattern, options))
{
Console.WriteLine("'{0}' found at index {1}.", m.Value, m.Index);
}
}
}
If you are willing to accept the extra "_" and other white space characters then I simplified your pattern as follows:
var pat = #"(<(?'tag'[ph0-9figc]+)>)(?'body'([\wäöüÄÖÜß\p{P}\s])+)(<\/\k'tag'>)";
And the regular expression removing the CR-LF is:
var body = m.Groups["body"].Value
.Replace(Environment.NewLine, " ")
.Replace("\r", " ")
.Replace("\n", " ");
var tag = m.Groups["tag"].Value;
var noCrLf = re.Replace(text, m => $"<{tag}>{body}</{tag}>");
Though looking at your data, I may not have understood what you are after. One of your tags, for example, is not matched by your tag pattern "[ph0-9figc]+". If I did not understand your concern, please straighten me out.
I have tried to create XML log file using log4net and it create log successfully but without root element
my question how to create the root element
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
<file value="logger.xml" type="log4net.Util.PatternString" />
<appendToFile value="true"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="20"/>
<maximumFileSize value="10000KB"/>
<staticLogFileName value="true"/>
<preserveLogFileNameExtension value="true" />
<layout type="Log4net1.CustomXmlLayoutSchemaLog4j">
<locationInfo value="true" />
</layout>
</appender>
<event logger="SomeName2" time="4/16/2019 2:45:15 PM" level="ERROR" thread="1"><message>Exception Caught: </message><properties><data name="log4jmachinename" value="IbrahimS-LPT" /><data name="log4japp" value="Log4net.exe" /><data name="log4net:Identity" value="" /><data name="log4net:UserName" value="SSS-PROCESS\ibrahims" /><data name="log4net:HostName" value="IbrahimS-LPT" /></properties><throwable>System.InvalidCastException: hhhhh ---> System.Exception: sub
--- End of inner exception stack trace ---</throwable><locationInfo class="Log4net.LoggingHelper" method="LogError" file="" line="0" /></event>
<event logger="SomeName2" time="4/16/2019 2:45:15 PM" level="ERROR" thread="1"><message>Exception Caught: </message><properties><data name="log4jmachinename" value="IbrahimS-LPT" /><data name="log4japp" value="Log4net.exe" /><data name="log4net:Identity" value="" /><data name="log4net:UserName" value="SSS-PROCESS\ibrahims" /><data name="log4net:HostName" value="IbrahimS-LPT" /></properties><throwable>System.InvalidCastException: hhhhh ---> System.Exception: sub
--- End of inner exception stack trace ---</throwable><locationInfo class="Log4net.LoggingHelper" method="LogError" file="" line="0" /></event>
when trying to open the file in xml format I got this error Unable to parse any XML input
but when add root element manually i am able to view
i need to be like this
<app>
<event logger="SomeName2" time="4/16/2019 2:45:15 PM" level="ERROR" thread="1"></event>
<event logger="SomeName2" time="4/16/2019 2:45:15 PM" level="ERROR" thread="1"></event>
</app>
class CustomXmlLayoutSchemaLog4j : XmlLayoutBase
{
#region Static Members
/// <summary>
/// The 1st of January 1970 in UTC
/// </summary>
private static readonly DateTime s_date1970 = new DateTime(1970, 1, 1);
#endregion
#region Constructors
/// <summary>
/// Constructs an XMLLayoutSchemaLog4j
/// </summary>
public CustomXmlLayoutSchemaLog4j() : base()
{
}
/// <summary>
/// Constructs an XMLLayoutSchemaLog4j.
/// </summary>
/// <remarks>
/// <para>
/// The <b>LocationInfo</b> option takes a boolean value. By
/// default, it is set to false which means there will be no location
/// information output by this layout. If the the option is set to
/// true, then the file name and line number of the statement
/// at the origin of the log statement will be output.
/// </para>
/// <para>
/// If you are embedding this layout within an SMTPAppender
/// then make sure to set the <b>LocationInfo</b> option of that
/// appender as well.
/// </para>
/// </remarks>
public CustomXmlLayoutSchemaLog4j(bool locationInfo) : base(locationInfo)
{
}
#endregion
#region Public Properties
/// <summary>
/// The version of the log4j schema to use.
/// </summary>
/// <remarks>
/// <para>
/// Only version 1.2 of the log4j schema is supported.
/// </para>
/// </remarks>
public string Version
{
get { return "1.2"; }
set
{
if (value != "1.2")
{
throw new ArgumentException("Only version 1.2 of the log4j schema is currently supported");
}
}
}
#endregion
/* Example log4j schema event
<event logger="first logger" level="ERROR" thread="Thread-3" timestamp="1051494121460">
<message><![CDATA[errormsg 3]]></message>
<NDC><![CDATA[third]]></NDC>
<MDC>
<data name="some string" value="some valuethird"/>
</MDC>
<throwable><![CDATA[java.lang.Exception: someexception-third
at org.apache.log4j.chainsaw.Generator.run(Generator.java:94)
]]></throwable>
<locationInfo class="org.apache.log4j.chainsaw.Generator"
method="run" file="Generator.java" line="94"/>
<properties>
<data name="log4jmachinename" value="windows"/>
<data name="log4japp" value="udp-generator"/>
</properties>
</event>
*/
/* Since log4j 1.3 the MDC has been combined into the properties element */
/// <summary>
/// Actually do the writing of the xml
/// </summary>
/// <param name="writer">the writer to use</param>
/// <param name="loggingEvent">the event to write</param>
/// <remarks>
/// <para>
/// Generate XML that is compatible with the log4j schema.
/// </para>
/// </remarks>
override protected void FormatXml(XmlWriter writer, LoggingEvent loggingEvent)
{
// Translate logging events for log4j
Header = "App";
// Translate hostname property
if (loggingEvent.LookupProperty(LoggingEvent.HostNameProperty) != null &&
loggingEvent.LookupProperty("log4jmachinename") == null)
{
loggingEvent.GetProperties()["log4jmachinename"] = loggingEvent.LookupProperty(LoggingEvent.HostNameProperty);
}
// translate appdomain name
if (loggingEvent.LookupProperty("log4japp") == null &&
loggingEvent.Domain != null &&
loggingEvent.Domain.Length > 0)
{
loggingEvent.GetProperties()["log4japp"] = loggingEvent.Domain;
}
// translate identity name
if (loggingEvent.Identity != null &&
loggingEvent.Identity.Length > 0 &&
loggingEvent.LookupProperty(LoggingEvent.IdentityProperty) == null)
{
loggingEvent.GetProperties()[LoggingEvent.IdentityProperty] = loggingEvent.Identity;
}
// translate user name
if (loggingEvent.UserName != null &&
loggingEvent.UserName.Length > 0 &&
loggingEvent.LookupProperty(LoggingEvent.UserNameProperty) == null)
{
loggingEvent.GetProperties()[LoggingEvent.UserNameProperty] = loggingEvent.UserName;
}
// Write the start element
writer.WriteStartElement("event");
writer.WriteAttributeString("logger", loggingEvent.LoggerName);
// Calculate the timestamp as the number of milliseconds since january 1970
//
// We must convert the TimeStamp to UTC before performing any mathematical
// operations. This allows use to take into account discontinuities
// caused by daylight savings time transitions.
TimeSpan timeSince1970 = loggingEvent.TimeStampUtc - s_date1970;
writer.WriteAttributeString("time", DateTime.Now.ToString());
writer.WriteAttributeString("level", loggingEvent.Level.DisplayName);
writer.WriteAttributeString("thread", loggingEvent.ThreadName);
// Append the message text
writer.WriteStartElement("message");
Transform.WriteEscapedXmlString(writer, loggingEvent.RenderedMessage, this.InvalidCharReplacement);
writer.WriteEndElement();
object ndcObj = loggingEvent.LookupProperty("NDC");
if (ndcObj != null)
{
string valueStr = loggingEvent.Repository.RendererMap.FindAndRender(ndcObj);
if (valueStr != null && valueStr.Length > 0)
{
// Append the NDC text
writer.WriteStartElement("NDC");
Transform.WriteEscapedXmlString(writer, valueStr, this.InvalidCharReplacement);
writer.WriteEndElement();
}
}
// Append the properties text
PropertiesDictionary properties = loggingEvent.GetProperties();
if (properties.Count > 0)
{
writer.WriteStartElement("properties");
foreach (System.Collections.DictionaryEntry entry in properties)
{
writer.WriteStartElement("data");
writer.WriteAttributeString("name", (string)entry.Key);
// Use an ObjectRenderer to convert the object to a string
string valueStr = loggingEvent.Repository.RendererMap.FindAndRender(entry.Value);
writer.WriteAttributeString("value", valueStr);
writer.WriteEndElement();
}
writer.WriteEndElement();
}
string exceptionStr = loggingEvent.GetExceptionString();
if (exceptionStr != null && exceptionStr.Length > 0)
{
// Append the stack trace line
writer.WriteStartElement("throwable");
Transform.WriteEscapedXmlString(writer, exceptionStr, this.InvalidCharReplacement);
writer.WriteEndElement();
}
if (LocationInfo)
{
LocationInfo locationInfo = loggingEvent.LocationInformation;
writer.WriteStartElement("locationInfo");
writer.WriteAttributeString("class", locationInfo.ClassName);
writer.WriteAttributeString("method", locationInfo.MethodName);
writer.WriteAttributeString("file", locationInfo.FileName);
writer.WriteAttributeString("line", locationInfo.LineNumber);
writer.WriteEndElement();
}
writer.WriteEndElement();
}
}
What you need to do is the next:
before this part of code:
// Write the start element
writer.WriteStartElement("event");
writer.WriteAttributeString("logger", loggingEvent.LoggerName);
You'll need to add this line:
writer.WriteStartElement("App");
Also, add a writer.WriteEndElement(); after the last one in you current code.
So your code will look like:
// Write the start element
writer.WriteStartElement("App");
writer.WriteStartElement("event");
writer.WriteAttributeString("logger", loggingEvent.LoggerName);
.
.
.
.
writer.WriteEndElement();
writer.WriteEndElement();
Since there might be very few people with Experience in TestStand and Vector XLDriver (here used for automotive CAN bus), I would really appreciate educated guesses ...
TestStand 2014 64Bit
I have an Action Step in a Sequence. It uses a function of a C# Dll.
The function runs perfectly but if I try to insert one of the two lines in the class scope before the function:
public XLDriver xlDriver = new XLDriver();
or
private static XLDriver xlDriver = new XLDriver();
it doesn't work in TestStand. The latter works fine, when calling the function from a C# Main().
In TestStand I receive the following
An exception occurred inside the call to .NET member 'myMember':
System.NullReferenceException: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
bei vxlapi_NET.C_XLapiLoader..ctor()
bei vxlapi_NET.XLDriver..ctor()
bei myNameSpace.myClass..ctor() in myFile.cs:Line 27.
The Phrase "Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt." can be translated as "The object reference has not been linked to an object instance."
Without that XLDriver line it works in TestStand. Using it in another C# Main() it works anyway. Nothing else changed.
The vxlapi_NET.dll calls the vxlapi.dll or the vxlapi64.dll. Since I already deleted the 32-bit Version and tried again, the vxlapi_NET.dll file might not call the wrong one.
If I use the my C# in another C# Project which uses the Dll and compiles to an executable, I can use it in TestStand. It calls the XL Driver perfectly.
So where is the difference in using an executable or a C# Dll in a TestStand Sequence Step?
Thanks.
I refactored vxlapi_NET, problem is in Assembly.GetEntryAssembly() method, GetEntryAssembly returns null.
// Decompiled with JetBrains decompiler
// Type: vxlapi_NET.C_XLapiLoader
// Assembly: vxlapi_NET, Version=9.0.0.26263, Culture=neutral,
....
namespace vxlapi_NET
{
internal class C_XLapiLoader
{
private string exeDirectory =
Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
....
According with .NET NUnit test - Assembly.GetEntryAssembly() is null
you may use
/// <summary>
/// Use as first line in ad hoc tests (needed by XNA specifically)
/// </summary>
public static void SetEntryAssembly()
{
SetEntryAssembly(Assembly.GetCallingAssembly());
}
/// <summary>
/// Allows setting the Entry Assembly when needed.
/// Use AssemblyUtilities.SetEntryAssembly() as first line in XNA ad hoc tests
/// </summary>
/// <param name="assembly">Assembly to set as entry assembly</param>
public static void SetEntryAssembly(Assembly assembly)
{
AppDomainManager manager = new AppDomainManager();
FieldInfo entryAssemblyfield = manager.GetType().GetField("m_entryAssembly", BindingFlags.Instance | BindingFlags.NonPublic);
entryAssemblyfield.SetValue(manager, assembly);
AppDomain domain = AppDomain.CurrentDomain;
FieldInfo domainManagerField = domain.GetType().GetField("_domainManager", BindingFlags.Instance | BindingFlags.NonPublic);
domainManagerField.SetValue(domain, manager);
}
....
SetEntryAssembly();
XLDriver xlDriver = new XLDriver();
...
i am trying to write an c# programm to define custom commands for cortana!
First of all i create an default app-application and load the VCD file...
I create a second project link this to the main project and create inside this a backgroundtask to handle the cortana requests!
Now cortana know my commands, but if i tell her something she is answering "Es ist etwas schief gelaufen" (in english: "it fails").
I think the BackgroundTask is not correctly called.
App.cs
namespace CortanaCommandsStart
{
/// <summary>
/// Stellt das anwendungsspezifische Verhalten bereit, um die Standardanwendungsklasse zu ergänzen.
/// </summary>
sealed partial class App : Application
{
/// <summary>
/// Initialisiert das Singletonanwendungsobjekt. Dies ist die erste Zeile von erstelltem Code
/// und daher das logische Äquivalent von main() bzw. WinMain().
/// </summary>
public App()
{
Microsoft.ApplicationInsights.WindowsAppInitializer.InitializeAsync(Microsoft.ApplicationInsights.WindowsCollectors.Metadata | Microsoft.ApplicationInsights.WindowsCollectors.Session);
this.InitializeComponent();
this.Suspending += OnSuspending;
}
/// <summary>
/// Wird aufgerufen, wenn die Anwendung durch den Endbenutzer normal gestartet wird. Weitere Einstiegspunkte
/// werden z. B. verwendet, wenn die Anwendung gestartet wird, um eine bestimmte Datei zu öffnen.
/// </summary>
/// <param name="e">Details über Startanforderung und -prozess.</param>
protected override async void OnLaunched(LaunchActivatedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
// App-Initialisierung nicht wiederholen, wenn das Fenster bereits Inhalte enthält.
// Nur sicherstellen, dass das Fenster aktiv ist.
if (rootFrame == null)
{
// Frame erstellen, der als Navigationskontext fungiert und zum Parameter der ersten Seite navigieren
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Zustand von zuvor angehaltener Anwendung laden
}
// Den Frame im aktuellen Fenster platzieren
Window.Current.Content = rootFrame;
}
if (rootFrame.Content == null)
{
// Wenn der Navigationsstapel nicht wiederhergestellt wird, zur ersten Seite navigieren
// und die neue Seite konfigurieren, indem die erforderlichen Informationen als Navigationsparameter
// übergeben werden
rootFrame.Navigate(typeof(MainPage), e.Arguments);
}
try {
StorageFile vcdStorageFile = await Package.Current.InstalledLocation.GetFileAsync(#"LEDControll.xml");
await VoiceCommandDefinitionManager.InstallCommandDefinitionsFromStorageFileAsync(vcdStorageFile);
System.Diagnostics.Debug.WriteLine("There was no error registering the Voice Command Definitions");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("There was an error registering the Voice Command Definitions", ex);
}
// Sicherstellen, dass das aktuelle Fenster aktiv ist
Window.Current.Activate();
}
/// <summary>
/// Wird aufgerufen, wenn die Navigation auf eine bestimmte Seite fehlschlägt
/// </summary>
/// <param name="sender">Der Rahmen, bei dem die Navigation fehlgeschlagen ist</param>
/// <param name="e">Details über den Navigationsfehler</param>
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
{
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
}
/// <summary>
/// Wird aufgerufen, wenn die Ausführung der Anwendung angehalten wird. Der Anwendungszustand wird gespeichert,
/// ohne zu wissen, ob die Anwendung beendet oder fortgesetzt wird und die Speicherinhalte dabei
/// unbeschädigt bleiben.
/// </summary>
/// <param name="sender">Die Quelle der Anhalteanforderung.</param>
/// <param name="e">Details zur Anhalteanforderung.</param>
private void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
//TODO: Anwendungszustand speichern und alle Hintergrundaktivitäten beenden
deferral.Complete();
}
}
}
Appxmanifest:
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" IgnorableNamespaces="uap mp">
<Identity Name="32ed3ec5-2e4a-4517-ae2b-842653ab8a8e" Publisher="CN=Flo" Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="32ed3ec5-2e4a-4517-ae2b-842653ab8a8e" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties>
<DisplayName>CortanaCommandsStart</DisplayName>
<PublisherDisplayName>Flo</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate" />
</Resources>
<Applications>
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="CortanaCommandsStart.App">
<uap:VisualElements DisplayName="CortanaCommandsStart" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" Description="CortanaCommandsStart" BackgroundColor="transparent">
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png">
</uap:DefaultTile>
<uap:SplashScreen Image="Assets\SplashScreen.png" />
</uap:VisualElements>
<Extensions>
<uap:Extension Category="windows.appService" EntryPoint="CortanaCommand.CortanaCommandService">
<uap:AppService Name="CortanaCommandService" />
</uap:Extension>
</Extensions>
</Application>
</Applications>
</Package>
CortanaCommand.cs
namespace CortanaCommand
{
public sealed class CortanaCommandService : IBackgroundTask
{
private VoiceCommandServiceConnection voiceServiceConnection;
private BackgroundTaskDeferral _deferral;
public async void Run(IBackgroundTaskInstance taskInstance)
{
_deferral = taskInstance.GetDeferral();
voiceServiceConnection.VoiceCommandCompleted += VoiceCommandCompleted;
AppServiceTriggerDetails triggerDetails = taskInstance.TriggerDetails as AppServiceTriggerDetails;
if (triggerDetails != null && triggerDetails.Name.Equals("CortanaCommandService"))
{
try
{
voiceServiceConnection = VoiceCommandServiceConnection.FromAppServiceTriggerDetails(triggerDetails);
VoiceCommand voiceCommand = await voiceServiceConnection.GetVoiceCommandAsync();
// Perform the appropriate command depending on the operation defined in VCD
VoiceCommandUserMessage userMessage = new VoiceCommandUserMessage();
switch (voiceCommand.CommandName)
{
case "LedChangeColor":
var destination = voiceCommand.Properties["color"][0];
SendCompletionMessageForDestination(destination);
break;
default:
LaunchAppInForeground();
break;
}
}
finally
{
_deferral.Complete();
}
}
}
private void VoiceCommandCompleted(VoiceCommandServiceConnection sender, VoiceCommandCompletedEventArgs args)
{
if (this._deferral != null)
{
this._deferral.Complete();
}
}
private async void SendCompletionMessageForDestination(string destination)
{
// Take action and determine when the next trip to destination
// Inset code here
// Replace the hardcoded strings used here with strings
// appropriate for your application.
// First, create the VoiceCommandUserMessage with the strings
// that Cortana will show and speak.
var userMessage = new VoiceCommandUserMessage();
userMessage.DisplayMessage = "Here’s your trip.";
userMessage.SpokenMessage = "Your trip to Vegas is on August 3rd.";
// Optionally, present visual information about the answer.
// For this example, create a VoiceCommandContentTile with an
// icon and a string.
var destinationsContentTiles = new List<VoiceCommandContentTile>();
// Create the VoiceCommandResponse from the userMessage and list
// of content tiles.
var response = VoiceCommandResponse.CreateResponse(userMessage, destinationsContentTiles);
// Ask Cortana to display the user message and content tile and
// also speak the user message.
await voiceServiceConnection.ReportSuccessAsync(response);
}
private async void LaunchAppInForeground()
{
var userMessage = new VoiceCommandUserMessage();
userMessage.SpokenMessage = "Launching Adventure Works";
var response = VoiceCommandResponse.CreateResponse(userMessage);
// When launching the app in the foreground, pass an app
// specific launch parameter to indicate what page to show.
response.AppLaunchArgument = "showAllTrips=true";
await voiceServiceConnection.RequestAppLaunchAsync(response);
}
}
}
VCD:
<?xml version="1.0" encoding="utf-8"?>
<VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.2">
<CommandSet xml:lang="de-de" Name="LEDControll">
<CommandPrefix>LED</CommandPrefix>
<Example>Steuere die LEDs</Example>
<Command Name="LedChangeColor">
<Example>LED Farbe grün</Example>
<ListenFor>farbe {color}</ListenFor>
<Feedback>Farbe wird geändert in {color}</Feedback>
<VoiceCommandService Target="CortanaCommandService"/>
</Command>
<PhraseList Label="color">
<Item> grün </Item>
<Item> blau </Item>
<Item> rot </Item>
</PhraseList>
</CommandSet>
</VoiceCommands>
Thank you, for your help!
Just adding the answer here so it's clear:
To ensure that the background task is added to the App Package properly, you can add a reference from the startup project to the background task project within VS:
Right click on references in the startup project
Go to Add Reference
Select "Projects" on the left
Tick the box next to the project containing the background task.
Hit OK.
This ensures that VS will build and copy the background task into the package when you go to deploy it. Otherwise, you run into difficult to debug problems like this.
Typically you can tell this has happened when you've triple-checked that the Package manifest uap:Extension entry has the right details, but can't get a breakpoint to hit in the background task when you try to activate it. I'll also check to see if there are any event log type entries that can be looked up to see this more easily.
The results from a rehosted designer (WF4) have an issue when adding a default value to an argument. Every other case seems to work fine. This is the (abridged) xaml of a (nearly) empty workflow.
<Activity mc:Ignorable="sap" x:Class="{x:Null}" this:_b40c.NewArg="test" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities"
xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mva="clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities" xmlns:sap="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation"
xmlns:scg="clr-namespace:System.Collections.Generic;assembly=mscorlib" xmlns:this="clr-namespace:" xmlns:twc="clr-namespace:Telogis.Workflow.CustomerApi;assembly=Telogis.Workflow.Activities"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:Members>
<x:Property Name="AuthenticationHeader" Type="InArgument(twc:AuthenticationHeader)" />
<x:Property Name="BaseTdeUri" Type="InArgument(x:Uri)" />
<x:Property Name="NewArg" Type="InArgument(x:String)" />
</x:Members>
<sap:VirtualizedContainerService.HintSize>654,676</sap:VirtualizedContainerService.HintSize>
<mva:VisualBasic.Settings>Assembly references and imported namespaces serialized as XML namespaces</mva:VisualBasic.Settings>
<Flowchart />
</Activity>
Specifically when default value is added, the following additions are made to the definition: this:_b40c.NewArg="test" and xmlns:this="clr-namespace:"
xmlns:this="clr-namespace:" is invalid as it doesn't point anywhere and can't be parsed with ActivityXamlServices.Load(stream); (it throws XamlObjectWriterException: "'Cannot set unknown member '{clr-namespace:}_b40c.NewArg'.' ...)
This seems to occur whatever the specified type of the argument is.
Any idea what could be causing this?
Update
I was using an ActivityBuilder to utilise the activity in the first place. This was fine, but as I hadn't provided it with a name, it had to generate a key, in the example above _b40c. ActivityXamlServices.Load has some kind off issue processing these keys. However, simply defining a name for ActivityBuilder seems to do the trick.
This still doesn't answer why it creates xmlns:this="clr-namespace:" without an actual namespace.
Your workflow xaml is invalid. I'm not sure where you got it or how it got into this state.
I can tell this because
<Activity
x:Class="{x:Null}"
this:_b40c.NewArg="test"
xmlns:this="clr-namespace:"
the clr-style namespace declaration is invalid. It should read
clr-namespace:Some.Namespace.In.The.Current.Assembly
or
clr-namespace:Some.Namespace;assembly=SomeAssemblyWithSomeNamespace
As your declaration is malformed, the this xml namespace cannot be parsed by the XamlObjectWriter in order to determine what namespace/assembly your _b40c type exists in. Also, that looks highly suspicious as well. And I've never seen an x:Class set to null before. That also strikes me as malformed.
If I understand well - this is WF Designer bug.
I've faced with this problem when I had had to support default value definition for InArgument<T> in my custom WF designer. I still surprised lack of support for this basic procedure.
There are 2 reason of failure:
Definition of {x:Null} in x:Class attribute
Invalid definition of xmlns:this attribute
And the main problem is invalid definition of Argument's default value: this:_effe.MyArgument="asd". The definition of default value for argument should be equal to this:MyXamlClassName.MyArgument="asd". For example, if your x:Cass definition is x:Class="MyNamespace.MyClass", Argument definition should be this:MyClass.MyArgument="asd".
I resolved it by intervention into XAML saving process:
After calling of
_workflowDesigner.Save(_editedFile);
I added these two lines:
#region x:Class and Argument<T> default value issues solution
await CreateAttributeValue(_editedFile, ConstXClassAttributeName, typeof(App).Namespace + "." + Path.GetFileNameWithoutExtension(_editedFile));
//should finish first operation before second operation begins to avoid I/O exception
await CreateAttributeValue(_editedFile, ConstNamespaceAttributeName, ConstXamlClrNamespace + typeof(App).Namespace);
await RepairArgsAttributes(_editedFile);
#endregion
This is the methods definition:
/// <summary>
/// Reason of using of this method: bug in workflow designer. When you save your xaml file, WF Designer assign "{x:Null}" to x:Class attribute
/// Bug: In addition, if you want to set default value for your InArgument<T>, it defines attribute "this" (namespace declaration) with empty value. When you try to open your file, designer fails to parse XAML.
/// </summary>
/// <param name="editedFile"></param>
/// <param name="attribteName"></param>
/// <param name="attributeValueToReplace"></param>
private static async Task CreateAttributeValue(string editedFile, string attribteName, string attributeValueToReplace)
{
XmlDocument xmlDoc = new XmlDocument();
await Task.Run(() => xmlDoc.Load(editedFile));
await Task.Run(() =>
{
var attributteToReplace = xmlDoc.FirstChild.Attributes?[attribteName];
if (null != attributteToReplace)
{
xmlDoc.FirstChild.Attributes[attribteName].Value = attributeValueToReplace;
xmlDoc.Save(editedFile);
}
});
}
/// <summary>
/// Bug in Workflow designer: workflow designer saves declaration for In/Out Arguments in invalid format. Means, that it is unable to open the same file it saved itself. This method fixes the Arguments declaration in XAML xmlns
/// </summary>
/// <param name="editedFile"></param>
/// <returns></returns>
private async Task RepairArgsAttributes(string editedFile)
{
XmlDocument xmlDoc = new XmlDocument();
await Task.Run(() => xmlDoc.Load(editedFile));
await Task.Run(() =>
{
for (int i = 0; i < xmlDoc.FirstChild.Attributes.Count; i++)
{
if (xmlDoc.FirstChild.Attributes[i].Name.StartsWith(ConstInvalidArgStarts))
{
string innvalidAttrName = xmlDoc.FirstChild.Attributes[i].Name;//extraction of full argument declaration in xmlns
string[] oldStrings = innvalidAttrName.Split('.');//extraction of arguemnt name string
string localName = Path.GetFileNameWithoutExtension(editedFile) + "." + oldStrings[1];//build valid argment declaration without perfix
string valueBackup = xmlDoc.FirstChild.Attributes[i].Value;//saving of default value of Arguemnt<T>
xmlDoc.FirstChild.Attributes.RemoveNamedItem(xmlDoc.FirstChild.Attributes[i].Name);//removal of invalid Arguemnt declaration with default value. WARNING: when you remove attribue, at this moment you have another item at the place xmlDoc.FirstChild.Attributes[i]
//definition of new valid attribute requries: set separelly attribute prefix, localName (not "name" - it causes invalid attribute definition) and valid namespace url (in our case it's namespace deifinition in "this")
XmlAttribute attr = xmlDoc.CreateAttribute(ConstArgPrefix, localName, xmlDoc.FirstChild.Attributes[ConstNamespaceAttributeName].Value);
attr.Value = valueBackup;
xmlDoc.FirstChild.Attributes.InsertBefore(attr, xmlDoc.FirstChild.Attributes[i]);//define new correct Argument declaration attribute at the same place where was invalid attribute. When you put valid attribute at the same place your recover valid order of attributes that was changed while removal of invalid attribute declaration
}
}
xmlDoc.Save(editedFile);
});
}
The constants definition are:
#region Constants
private const string ConstXClassAttributeName = "x:Class";
private const string ConstXamlClrNamespace = "clr-namespace:";
private const string ConstNamespaceAttributeName = "xmlns:this";
private const string ConstInvalidArgStarts = #"this:_";
private const string ConstArgPrefix = #"this";
#endregion
This solution should resolve your issue too.