System.XML on XAMARIN forms project - c#

I am trying to use XmlDocument class **
and **XmlDocument .Load(..) function
on the Portable Project of XAMARIN.Forms Portable solution with visual studio community.
The compiler says that "The type or namespace name 'XmlDocument' could not be found (are you missing a using directive or an assembly reference?"
If i go in References it don't allow me to add the System.XML namespace (there is no) and if i browse file and go to system.xml.dll it says me that the file could not be added because this component is already automatically referenced by build system.
what i can to do to use the class??
NOTE:
in .Droid and .IOS project there is a referenc to System.xml and in those projects I can use XmlDocument class.

PCL doesn't support XmlDocument. You can use System.Xml.Linq.XDocument instead.

The XmlDocument class is not available for use in a PCL library, as you can see on its documentation page under Version Information. (Compare to the Version Information section of the XmlDictionary class - notice how this class has Portable Class Library available while XmlDocument does not.)
If you want to use an XmlDocument, you'll have to create a dependency service and implement it separately under both Android and iOS versions.

I had no trouble adding XML to my project:
using System.Xml;
using System.Xml.Serialization;
public string ToXML(Object oObject)
{
XmlDocument xmlDoc = new XmlDocument();
XmlSerializer xmlSerializer = new XmlSerializer(oObject.GetType());
using (MemoryStream xmlStream = new MemoryStream())
{
xmlSerializer.Serialize(xmlStream, oObject);
xmlStream.Position = 0;
xmlDoc.Load(xmlStream);
return xmlDoc.InnerXml;
}
}
After that the XML string can be shared:
public MvxCommand ShareWaypoints => new MvxCommand(ShareWaypointsAsync);
public async void ShareWaypointsAsync()
{
try
{
string strXML = "";
foreach (var wp in waypoints)
{
strXML += ToXML(wp);
}
if (strXML != "")
await Share.RequestAsync(new ShareTextRequest
{
Text = strXML,
Title = "Share Text"
});
}
catch (Exception ex)
{
await _userDialogs.AlertAsync(ex.Message);
}
}

Related

XmlReaderSettings.Schemas.Add() : The URI prefix is not recognized

I upgraded my old application in .Net 4.5. There are some obsolete methods warnings I was getting so thought to resolve them. One of the obsolete methods is XmlValidatingReader.
Looked up on the internet and found that XmlReaderSettings is a potential alternate of XmlValidatingReader.
// ==old code==
Hashtable _SchemasCache = new Hashtable();
XmlReader xmlReader = new XmlTextReader(xmlStream);
XmlValidatingReader validatingReader = new XmlValidatingReader(xmlReader);
validatingReader.Schemas.Add(root.Namespace, schemaLocation); // both parametres are string. No error
_SchemasCache.Add(schemaLocation, validatingReader.Schemas);
// ==new code==
var schemaLocation = "res://somepath/Messages.xsd";
XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas.Add(root.Namespace, schemaLocation); // this line gives error
_SchemasCache.Add(schemaLocation, settings.Schemas);
old code doesn't give any error but the new code gives an error of The URI prefix is not recognized. I couldn't find the reason for this behavior of settings.Schemas.Add(), as it is working fine with XmlValidatingReader. Can anyone help with this?
Edit: Here value of schemaLocation is "res://somepath/Messages.xsd". Because schemaLocation has no Http: or https:// or not a local resource, that is why the error is occurring. How can I add schemas with these values using XmlReaderSettings
Edit 2: as this XSD is an embedded resource, I found some code online for this scenario. I made below code changes.
Assembly asm = Assembly.Load("AssemblyNameWhereXSDis");
Uri uri = new Uri(#"res://p.a.t.h/Autorisatie/Messages.xsd");
string resourceName1 = asm.GetName().Name + uri.AbsolutePath.Replace("/", ".");
using (Stream schemaStream = myAssembly.GetManifestResourceStream(resourceName1))
{
using (XmlReader schemaReader = XmlReader.Create(schemaStream)) // this line gives error : value(schemaStream) cannot be null
{
settings.Schemas.Add(root.Namespace, schemaReader);
}
}
here, the value of schemaStream is null. And the value of resourceName1 is assemblyname.folder.Message.xsd.
I have made Message.xsd as Embedded Resource from Visual Studio but still not working.
Source of issue
As you figured yourself - URI has to point to a REAL file somewhere - either a URL (HTTP/HTTPS) or a local file ("C:\...").
So, if you prefer using an Embedded Resource instead, you need to use a fully-specified path in the following form:
"Namespace.FolderName.Filename.Extension"
Example
using System;
using System.Linq;
using System.Reflection;
using System.Xml;
// ...
// get full resourceName from current assembly using Linq
var messagesResourceFullName = Assembly.GetExecutingAssembly()
.GetManifestResourceNames()
.Where(n => n.EndsWith("Messages.xsd"));
using (var schemaStream = asm.GetManifestResourceStream(messagesResourceFullName))
{
if (schemaStream == null) throw new FileNotFoundException();
using (var schemaReader = XmlReader.Create(schemaStream))
{
settings.Schemas.Add(root.Namespace, schemaReader);
}
}
source
Add this line in your code :
using System.Linq;

How do I create the .docx document with Microsoft.Office.Interop.Word?

How do I create the .docx document with Microsoft.Office.Interop.Word from List? or the best way is to add docx.dll?
http://www.c-sharpcorner.com/UploadFile/scottlysle/using-the-docx-dll-to-programmatically-create-word-documents/
Update. May be my first question is a litle incorrect. What is the difference between Microsoft.Office.Interop.Word and DocX.dll? Do I need Microsft Word for creating and opening .docx document in both cases?
upd: It seems like openxml sdk is now being installed via nuget, take a look at their github repo https://github.com/OfficeDev/Open-XML-SDK
After installing OpenXML SDK you will able to reference DocumentFormat.OpenXml assembly: Add Reference -> Assemblies ->
Extensions -> DocumentFormat.OpenXml. Also you will need to reference WindowsBase.
Than you will be able to generate document, for example, like this:
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
namespace MyNamespace
{
class Program
{
static void Main(string[] args)
{
using (var document = WordprocessingDocument.Create(
"test.docx", WordprocessingDocumentType.Document))
{
document.AddMainDocumentPart();
document.MainDocumentPart.Document = new Document(
new Body(new Paragraph(new Run(new Text("some text")))));
}
}
}
}
Also you can use Productivity Tool (the same link) to generate code from document. It can help to understand how work with SDK API.
You can do the same with Interop:
using System.Reflection;
using Microsoft.Office.Interop.Word;
using System.Runtime.InteropServices;
namespace Interop1
{
class Program
{
static void Main(string[] args)
{
Application application = null;
try
{
application = new Application();
var document = application.Documents.Add();
var paragraph = document.Paragraphs.Add();
paragraph.Range.Text = "some text";
string filename = GetFullName();
application.ActiveDocument.SaveAs(filename, WdSaveFormat.wdFormatDocument);
document.Close();
}
finally
{
if (application != null)
{
application.Quit();
Marshal.FinalReleaseComObject(application);
}
}
}
}
}
But in this case you should reference COM type library Microsoft. Word Object Library.
Here are very useful things about COM interop: How do I properly clean up Excel interop objects?
If you don't want to use Microsoft interop office then
I really liked this
//Add reference DocX.dll
using Novacode;
// reference to the working document.
static DocX gDocument;
public void CreateWithOpenDoc(string _fileName, string _saveAs, int _LeadNo)
{
if (File.Exists(_fileName))
{
gDocument = DocX.Load(_fileName);
//--------------------- Make changes -------------------------------
// Strong-Type
Dictionary<string, string> changesList = GetChangesList(_LeadNo, dt.Rows[0]);
foreach (KeyValuePair<string, string> keyValue in changesList)
{
gDocument.ReplaceText(keyValue.Key.ToString().Trim(), keyValue.Value.ToString().Trim(), false);
}
//------------------------- End of make changes ---------------------
gDocument.SaveAs(_saveAs);
}
}
take reference
C-sharp corner
If you don't know how to access office 2016 interop objects, the link (https://social.msdn.microsoft.com/Forums/vstudio/en-US/55fe7d16-998b-4c43-9746-45ff35310158/office-2016-interop-assemblies?forum=exceldev) can help to you.
After this, You can try #Evgeny Timoshenko's example.
class Program
{
static void Main(string[] args)
{
Application application = null;
try
{
application = new Application();
var document = application.Documents.Add();
var paragraph = document.Paragraphs.Add();
paragraph.Range.Text = "some text";
string filename = GetFullName();
application.ActiveDocument.SaveAs(filename, WdSaveFormat.wdFormatDocument);
document.Close();
}
finally
{
if (application != null)
{
application.Quit();
Marshal.FinalReleaseComObject(application);
}
}
}
}

Dealing with xsd:include XSDs as an embedded resource in Visual Studio

I have a set of XSDs that validate against XMLSPY and against Java code. I need to bring this set of XSDs as an embedded resource in Visual Studio 2012 .net. Unfortunately I am getting an error that a global element has already been declared when trying to resolve them with a custom XmlResolver to deal with the xsd:include. Error is strange because the element is declared only once.
Visual Studio Solution
|----------- Visual Studio Project
|----------- Schemas (Embedded Resource)
|----------- Directory A
|------------ set of XSDs that are referenced by XSDs in Directory B and to a globaltype definition file located in this directory
|----------- Directory B
|------------- set of XSDs that reference each other and those in Directory A, the XSD call from the main is located here
Validating Util Class
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;
namespace ABC.XYZ.Utils
{
public static class XmlUtil
{
private static bool isValid;
public static bool ValidateXml(string targetNamespace, string schemaUri, string xml)
{
isValid = true;
var schemaReaderSettings = new XmlReaderSettings() { ValidationType = ValidationType.Schema };
schemaReaderSettings.ValidationEventHandler += MyValidationHandler;
schemaReaderSettings.Schemas.XmlResolver = new XmlResourceResolver();
var schemaReader = XmlReader.Create(GetSchemaStream(schemaUri), schemaReaderSettings);
schemaReaderSettings.Schemas.Add(targetNamespace, schemaReader);
var x = XElement.Parse(xml);
var sr = new System.IO.StringReader(x.ToString());
XmlReader validatingReader = XmlReader.Create(sr, schemaReaderSettings);
while (validatingReader.Read())
{
}
validatingReader.Close();
return isValid;
}
private static void MyValidationHandler(object sender, ValidationEventArgs args)
{
Console.WriteLine("***Validation error");
Console.WriteLine("\tSeverity:{0}", args.Severity);
Console.WriteLine("\tMessage:{0}", args.Message);
isValid = false;
}
private static Stream GetSchemaStream(string relativeFileName)
{
var resourceFileName =
Assembly.GetExecutingAssembly()
.GetManifestResourceNames()
.FirstOrDefault(p => p.EndsWith(relativeFileName));
return Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceFileName);
}
}
}
Custom XmlResolver
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace ABC.XYZ.Utils
{
public class XmlResourceResolver : XmlResolver
{
public const string AssemblyDefaultNamespace = "ABC.XYZ";
public const string SchemasNamespace = "Schemas";
public override Uri ResolveUri(Uri baseUri, string relativeUri)
{
var result = new UriBuilder("res://", AssemblyDefaultNamespace, -1, SchemasNamespace.Replace(".", "/"));
result.Path += "/" + relativeUri.Replace("../", "/").TrimStart('/');
return result.Uri;
}
public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
{
if (absoluteUri.Scheme != "res") return null;
Debug.WriteLine("Loading resource based on location {0}", absoluteUri);
var assembly = Assembly.GetExecutingAssembly();
var name = String.Format(CultureInfo.InvariantCulture, "{0}{1}",
absoluteUri.Host,
absoluteUri.GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped).Replace("/", "."));
// try for an exact match based on schemaLocation hint path
var resourceName = (from x in assembly.GetManifestResourceNames()
where name.Equals(x, StringComparison.OrdinalIgnoreCase)
select x).FirstOrDefault();
// if not match based on filename alone
if (resourceName == null)
{
var schemaDocumentName = Path.GetFileName(absoluteUri.AbsolutePath);
Debug.WriteLine("Unable to locate exact match, looking for match based on filename {0}", schemaDocumentName);
resourceName = (from x in assembly.GetManifestResourceNames()
where x.Contains(SchemasNamespace) &&
x.EndsWith("." + schemaDocumentName, StringComparison.OrdinalIgnoreCase)
select x).FirstOrDefault();
}
Debug.WriteLine("Loading resource {0}", resourceName);
var stream = assembly.GetManifestResourceStream(resourceName);
return stream;
}
}
}
Any insights into this problem with be greatly appreciated.
XSD 1.0 encourages but does not require validators to detect multiple inclusions (or imports) of the same schema document and include them only once.
The result is that including the same schema document more than once from multiple other schema documents is the simplest way to create interoperability nightmares with XSD. (Not the only way, just the simplest way.) If you own the schema documents, segregate all inclusions and all schema-location information on imports into a driver file and delete all includes and all schema-location hints on imports from the 'normal' schema documents.
The problem is that when you're doing it with XMLSpy, the XSDs are files in the file system; what's happening then, for each file there's a base URI, and therefore resolvers will use that information to ensure that once an XSD is loaded, the same one is not loaded again, based on URI compare.
Now, the way you're doing it by loading as a stream from an assembly, all that information is gone (your stream doesn't have a base URI). Your resolver will keep loading the same XSD over and over again, from different places, thus creating this clash.
All the XSD processors I know, do not employ any other means to filter multiple inclusions of the same XSD content, but base source URI.
In .NET, the easiest way might be (again, depending on how complex your graph is) to try the solution in this post; the whole idea is to provide a base URI, which should give the info required to avoid multiple inclusions.
Another alternative might be to make sure in your custom resolver that for any given URI you're resolving, you only return once a stream (return null in all other cases). This is guaranteed to work as long as you're not using xsd:redefine composition (in which case the solution is to make a topological sort of the schema file graph and ensure all xsd:redefines are loaded first).
To #CMSperbergMcQueen point, an approach that is guaranteed to work is to refactor ALL the XSDs such that there's only one XSD embedded resource per namespace; each XSD would have all imports removed (technique called "dangling"). Add those XSDs to an XML Schema set as independent XSDs and compile. Unless you run into a .NET bug, the result should be a compiled XmlSchemaSet.

Showing ClickOnce deployment version on WPF application

I'm deploying now a WPF c# project and want to put the clickonce version (rather than the assembly or product version) on the screen title.
I used to do it in Win form application in the following way. But it seems that it is not the way in WPF applications. I searched on Google but didn't find anything. Please help.
if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed)
{
ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
lblVer.Text = "V" + ad.CurrentVersion.ToString();
}
else
lblVer.Text = "V" + Application.ProductVersion.ToString();
Try this:
public static Version GetPublishedVersion()
{
XmlDocument xmlDoc = new XmlDocument();
Assembly asmCurrent = System.Reflection.Assembly.GetExecutingAssembly();
string executePath = new Uri(asmCurrent.GetName().CodeBase).LocalPath;
xmlDoc.Load(executePath + ".manifest");
string retval = string.Empty;
if (xmlDoc.HasChildNodes)
{
retval = xmlDoc.ChildNodes[1].ChildNodes[0].Attributes.GetNamedItem("version").Value.ToString();
}
return new Version(retval);
}
What error do you get? There's no difference in the ClickOnce API's between Windows Forms and WPF. It is not dependent upon any UI framework.
Did you remember to add a reference to System.Deployment.dll?
using System;
using System.Deployment.Application;
namespace Utils
{
public class ClickOnce
{
public static Version GetPublishedVersion()
{
return ApplicationDeployment.IsNetworkDeployed
? ApplicationDeployment.CurrentDeployment.CurrentVersion
: System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
}
}
}
If you get an error about System.Deployment.Application, then Solution > Project > References > Add Reference > Assemblies > Framework > System.Deployment.
Do not parse the assembly XML for this information; you're relying on undocumented behaviour which simply happens to work 'for now'.
OK,
I found the problem.
I had to add reference to System.Deployment
That is why I couldn't use it. This dll is for winforms also.
This solution is similar to #Engin, but uses XPath.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("...");
XmlNamespaceManager ns = new XmlNamespaceManager(xmlDoc.NameTable);
ns.AddNamespace("asmv1", "urn:schemas-microsoft-com:asm.v1");
string xPath = "/asmv1:assembly/asmv1:assemblyIdentity/#version";
XmlNode node = xmlDoc.SelectSingleNode(xPath, ns);
string version = node.Value;

Using System.Json for non-Silverlight projects?

Any idea on how to do it? If not possible, what's a good JSON library for C#?
System.Json is now available in non-Silverlight projects via NuGet (.Net's package management system) and is hopefully going to be released as part of the core framework in vnext. The NuGet package is named JsonValue.
Imagine that we have the following JSON in the string variable json:
[{"a":"foo","b":"bar"},{"a":"another foo","b":"another bar"}]
We can get write the value "another bar" to the console using the following code:
using System.Json;
dynamic jsonObj = JsonValue.Parse(json);
var node = jsonObj[1].b;
System.Console.WriteLine(node.Value);
Here's an extenstion method to serialize any object instance to JSON:
public static class GenericExtensions
{
public static string ToJsonString<T>(this T input)
{
string json;
DataContractJsonSerializer ser = new DataContractJsonSerializer(input.GetType());
using (MemoryStream ms = new MemoryStream())
{
ser.WriteObject(ms, input);
json = Encoding.Default.GetString(ms.ToArray());
}
return json;
}
}
You'll need to add a reference to System.ServiceModel.Web to use the DataContractSerializer.
Scott Guthrie blogged about this
http://weblogs.asp.net/scottgu/archive/2007/10/01/tip-trick-building-a-tojson-extension-method-using-net-3-5.aspx
If you're just looking for JSON encoding/decoding, there is an official System.Web extension library from Microsoft that does it, odds are you probably already have this assembly (System.Web.Extensions):
http://msdn.microsoft.com/en-us/library/system.web.script.serialization.javascriptserializer.aspx
Example:
using System;
using System.Web.Script.Serialization;
class App
{
static void Main(string[] args = null)
{
JavaScriptSerializer jss = new JavaScriptSerializer();
String sJson = "{\"Name\": \"Your name\"}";
DesJson json = jss.Deserialize<DesJson>(sJson);
Console.WriteLine(json.Name);
}
}
class DesJson {
public string Name {get; set;}
}
Another option is to use Mono's implementation of System.Json,
I was able to backport it to C# 2.0 with a few minor changes.
You can simply download my C# 2.0 project from here.

Categories