Using VS 2012 and .NET 4.0, I have the following code which correctly deserializes an XML file:
XML File:
<?xml version="1.0"?>
<Codes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
<Code>
<AccpacCode>CA9998</AccpacCode>
<LAC>90699999999999999</LAC>
<SCSCode>SDI</SCSCode>
</Code>
<Code>
<AccpacCode>ORWC</AccpacCode>
<LAC>94199999999999999</LAC>
<SCSCode>WC</SCSCode>
</Code>
<Code>
<AccpacCode>AK9999</AccpacCode>
<LAC>90299999999999999</LAC>
<SCSCode>UI</SCSCode>
<ParentEmployerAccpacCode>AKSUTA</ParentEmployerAccpacCode>
</Code>
<Codes>
XSD File:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="Codes" xmlns="SerializeObservableCollection" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="Codes" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Code">
<xs:complexType>
<xs:sequence>
<xs:element name="AccpacCode" type="xs:string" minOccurs="0" />
<xs:element name="LAC" type="xs:string" minOccurs="0" />
<xs:element name="SCSCode" type="xs:string" minOccurs="0" />
<xs:element name="ParentEmployerAccpacCode" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
C# Code:
try
{
XmlSerializer _serializer = new XmlSerializer(typeof(Codes));
// A file stream is used to read the XML file into the ObservableCollection
using (StreamReader _reader = new StreamReader(#"LocalCodes.xml"))
{
var codes = _serializer.Deserialize(_reader) as Codes;
}
}
catch (Exception ex)
{
// Catch exceptions here
}
I would like to put the results of the deserialization into an ObservableCollection and have found examples that say the following should work:
ObservableCollection<Codes> CodeCollection;
...
try
{
XmlSerializer _serializer = new XmlSerializer(typeof(ObservableCollection<Codes>));
// A file stream is used to read the XML file into the ObservableCollection
using (StreamReader _reader = new StreamReader(#"LocalCodes.xml"))
{
CodeCollection = _serializer.Deserialize(_reader) as ObservableCollection<Codes>;
}
}
When I run this code I get an error message of "There is an error in XML document (2, 2)." and an inner exception of "<Codes xmlns=''> was not expected." I have seen mention of needing a default constructor to make this work and the Codes.cs class does have one (it is the file generated by VS 2012 by the XSD file). here is a snippet of the Codes.cs file:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18051
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
#pragma warning disable 1591
namespace SerializeObservableCollection {
/// <summary>
///Represents a strongly typed in-memory cache of data.
///</summary>
[global::System.Serializable()]
[global::System.ComponentModel.DesignerCategoryAttribute("code")]
[global::System.ComponentModel.ToolboxItem(true)]
[global::System.Xml.Serialization.XmlSchemaProviderAttribute("GetTypedDataSetSchema")]
[global::System.Xml.Serialization.XmlRootAttribute("Codes")]
[global::System.ComponentModel.Design.HelpKeywordAttribute("vs.data.DataSet")]
public partial class Codes : global::System.Data.DataSet {
private CodeDataTable tableCode;
private global::System.Data.SchemaSerializationMode _schemaSerializationMode = global::System.Data.SchemaSerializationMode.IncludeSchema;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")]
public Codes() {
this.BeginInit();
this.InitClass();
global::System.ComponentModel.CollectionChangeEventHandler schemaChangedHandler = new global::System.ComponentModel.CollectionChangeEventHandler(this.SchemaChanged);
base.Tables.CollectionChanged += schemaChangedHandler;
base.Relations.CollectionChanged += schemaChangedHandler;
this.EndInit();
}
What do I need to change/fix to get this to work and populate the ObservableCollection?
#BrianKE I doubt very much this will still be of use to you, but maybe it will be of use to someone else. I had the same problem as you today. Took me half the day to figure it out.
First, the message you are seeing is because the type you are specifying...
XmlSerializer _serializer = new XmlSerializer(typeof(ObservableCollection<Codes>));
..is not an ObservableCollection. If the type is wrong you get this error. Codes needs to be an observable collection for your statement to work.
What you need is root element, currently Codes is your root element, so you need a Class just for the root and then you have a number of Code elements under this. e.g.
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class MIGRATION : object, INotifyPropertyChanged, INotifyPropertyChanging
{
private string projectNameField;
private ObservableCollection<FileDescriptions> fileDescriptionsField;
//private FileDescriptions[] fileDescriptionsField;
/// <remarks/>
//[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
[XmlElement("ProjectName")]
public string ProjectName
{
get
{
return this.projectNameField;
}
set
{
this.RaisePropertyChanging("ProjectName");
this.projectNameField = value;
this.RaisePropertyChanged("ProjectName");
}
}
/// <remarks/>
[XmlElement("FileDescriptions")]
public ObservableCollection<FileDescriptions> FileDescriptions
{
get
{
return this.fileDescriptionsField;
}
set
{
this.fileDescriptionsField = value;
this.RaisePropertyChanged("FileDescriptions");
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if ((propertyChanged != null))
{
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
public event System.ComponentModel.PropertyChangingEventHandler PropertyChanging;
protected void RaisePropertyChanging(string propertyName)
{
System.ComponentModel.PropertyChangingEventHandler propertyChanging = this.PropertyChanging;
if ((propertyChanging != null))
{
propertyChanging(this, new System.ComponentModel.PropertyChangingEventArgs(propertyName));
}
}
}
So the Observable collection(s) is on the elements inside the deserialized Class. I know what you are talking about though, I have seen examples like you are describing, but I don't know what that is about. As far as I can tell the deserialize had nothing to do with observable collection. Unless maybe they have more than one root element? Or perhaps it is when you are not deserializing a whole XML, but just a part of one, would make sense.
Deserialize should be used only with content that was previously serialized using Serialize. Otherwise, you are just playing with fire.
You can easily open and iterate through an XML document using XDocument.
XDocument xml = XDocument.Load(filename);
var collection = new ObservableCollection<Code>();
foreach (XElement e in xml.Elements("code"))
{
collection.Add(new Code() { AccpacCode = e.Element("AccpacCode").Value,
LAC = e.Element("LAC").Value });
}
You can easily iterate in all xml.Elements and intiatiate a code object which you add to an ObservableCollection. The interface may flickr a bit though during the loading.
Related
First of all I would like to say hallo everybody - it's my first post here on SO. Now important stuff. I am writing some code in C# WPF .NET 4.0 which is based on serialization / deserialization built-in mechanizms. Everything was fine untill I decided to create a validation schema for my serialized xml file. All of this would be more clear when I show a bit my code:
Serialization
private void serializeObjectsToFile(string path)
{
using (var writer = new System.IO.StreamWriter(path))
{
var serializer = new XmlSerializer(myTopClass.GetType());
serializer.Serialize(writer, myTopClass);
writer.Flush();
}
}
Deserialization
private MyTopClass deserializeObjectsFromFile(string path)
{
using (var stream = System.IO.File.OpenRead(path))
{
var serializer = new XmlSerializer(typeof(MyTopClass));
return serializer.Deserialize(stream) as MyTopClass;
}
}
Validation
private bool validateXmlAgainstSchema(string pathToFile)
{
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("", schemaPath);
XDocument inputFile = XDocument.Load(pathToFile);
var isFileValid = true;
inputFile.Validate(schemas, (o, e) =>
{
MessageBox.Show(string.Format("Validation fails. {0}.", e.Message));
isFileValid = false;
});
return isFileValid;
}
Now let me introduce my Model which is serialized to xml file and for which I want to create a validation schema.
Top Class
namespace SerializationVsSchemaTest.Model
{
[Serializable]
public class MyTopClass
{
public int myTopItemOne { get; set; }
public int myTopItemTwo { get; set; }
public int myTopItemThree { get; set; }
public MyAbstractClass myTopAbstractItem { get; set; }
public MyTopClass()
{
myTopItemOne = 7;
myTopItemTwo = 8;
myTopItemThree = 9;
myTopAbstractItem = new ClassOne();
}
public override string ToString()
{
return string.Format("{0}\n{1}\n{2}\n{3}\n", myTopItemOne, myTopItemTwo, myTopItemThree, myTopAbstractItem.ToString());
}
}
}
Abstract Class - the most important stuff here and the root part of my question
namespace SerializationVsSchemaTest.Model
{
[XmlInclude(typeof(ClassOne))]
[XmlInclude(typeof(ClassTwo))]
public abstract class MyAbstractClass
{
}
}
ClassOne
namespace SerializationVsSchemaTest.Model
{
[Serializable]
public class ClassOne : MyAbstractClass
{
public int argOne;
public int argTwo;
public int argThree;
public ClassOne()
{
argOne = -1;
argTwo = -2;
argThree = -3;
}
}
}
ClassTwo
namespace SerializationVsSchemaTest.Model
{
[Serializable]
public class ClassTwo: MyAbstractClass
{
public byte argOne;
public byte argTwo;
public byte argThree;
public ClassTwo()
{
argOne = 4;
argTwo = 5;
argThree = 6;
}
}
}
Serialization result
<?xml version="1.0" encoding="utf-8"?>
<MyTopClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<myTopItemOne>7</myTopItemOne>
<myTopItemTwo>8</myTopItemTwo>
<myTopItemThree>9</myTopItemThree>
<myTopAbstractItem xsi:type="ClassOne">
<argOne>-1</argOne>
<argTwo>-2</argTwo>
<argThree>-3</argThree>
</myTopAbstractItem>
</MyTopClass>
My validation schema
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified" elementFormDefault="qualified">
<xsd:element name="MyTopClass">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="myTopItemOne" type="xsd:unsignedByte" />
<xsd:element name="myTopItemTwo" type="xsd:unsignedByte" />
<xsd:element name="myTopItemThree" type="xsd:unsignedByte" />
<xsd:element name="myTopAbstractItem">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="argOne" type="xsd:byte" />
<xsd:element name="argTwo" type="xsd:byte" />
<xsd:element name="argThree" type="xsd:byte" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
And the problem here is that this schema fails to validate my xml with following result:
Validation fails. Invalid type xsi:type 'ClassOne'. The strangest thing is that this schema is generated by Visual Studio 2013 using my serialized xml file. So it should match 100%... I hope You guys will help me somehow. Cheers!
I have been experimenting with Entity Framework 4.4, NHibernate 3.3.1.4000 and SQL Server and I have noticed a difference when it comes to fixing up the relationships when you commit your changes, and I was wondering what is the best practice or if I'm doing something wrong.
Here's what I tested. I have a classic Parent linked to n Children. I have 2 parents in the database with 20 children each. I load both parents, and I take the first child of the first parent and assign that child the second parent. I then commit the changes.
In EF, after I have saved, I can see that the count for the Children collection of both parents has been altered, so it fixed up the relationships.
However, when I do the same thing in NHibernate, the counts remain the same.
Here's my code setup to reproduce the issue.
POCOs:
public class Parent
{
public virtual int ParentId { get; set; }
public virtual string Name { get; set; }
public virtual IList<Child> Children { get; set; }
public Parent()
{
Children = new List<Child>();
}
}
public class Child
{
public virtual int ChildId { get; set; }
public virtual int ParentId { get; set; }
public virtual string Name { get; set; }
public virtual Parent Parent { get; set; }
}
NHibernate Parent mapping:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="ConsoleApplication1"
namespace="ConsoleApplication1">
<class name="Parent" table="Parents">
<id name="ParentId" column="ParentId" />
<property name="Name" column="Name" />
<bag name="Children" cascade="all">
<key column="ParentId"/>
<one-to-many class="Child"/>
</bag>
</class>
</hibernate-mapping>
NHibernate Child mapping:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="ConsoleApplication1"
namespace="ConsoleApplication1">
<class name="Child" table="Children">
<id name="ChildId" column="ChildId" />
<property name="Name" column="Name" />
<many-to-one name="Parent" class="Parent" column="ParentId" not-null="true" />
</class>
</hibernate-mapping>
EF DbContext:
public class Entities : DbContext
{
public DbSet<Parent> Parents { get; set; }
public DbSet<Child> Children { get; set; }
}
App.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler,NHibernate" />
</configSections>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">
NHibernate.Connection.DriverConnectionProvider
</property>
<property name="dialect">
NHibernate.Dialect.MsSql2005Dialect
</property>
<property name="connection.driver_class">
NHibernate.Driver.SqlClientDriver
</property>
<property name="connection.connection_string">
Data Source=localhost;Initial Catalog=MaintainRelationshipsNH;Integrated Security=True;
</property>
</session-factory>
</hibernate-configuration>
<connectionStrings>
<add
name="Entities"
providerName="System.Data.SqlClient"
connectionString="Server=localhost;Database=MaintainRelationshipsNH;Trusted_Connection=true;"/>
</connectionStrings>
</configuration>
Script to create the tables and data:
create table Parents (
ParentId INT not null,
Name NVARCHAR(255) null,
primary key (ParentId)
)
create table Children (
ChildId INT not null,
Name NVARCHAR(255) null,
ParentId INT not null,
primary key (ChildId)
)
alter table Children
add constraint FK_Children_Parents
foreign key (ParentId)
references Parents
declare #idChild int
insert into Parents (ParentId, Name) values (0, 'John');
set #idChild = 0
while #idChild < 20
begin
insert into Children (ChildId, Name, ParentId) values (#idChild, 'Child ' + convert(nvarchar(2), #idChild), 0);
set #idChild = #idChild + 1
end
insert into Parents (ParentId, Name) values (1, 'Julie');
while #idChild < 40
begin
insert into Children (ChildId, Name, ParentId) values (#idChild, 'Child ' + convert(nvarchar(2), #idChild), 1);
set #idChild = #idChild + 1
end
NHibernate test code:
System.Diagnostics.Debug.WriteLine("Test NHibernate:");
Configuration configuration = new Configuration();
configuration.Configure();
configuration.AddAssembly(typeof(Parent).Assembly);
ISessionFactory sessionFactory = configuration.BuildSessionFactory();
Parent parent0, parent1;
using (ISession session = sessionFactory.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
parent0 = session.Load<Parent>(0);
parent1 = session.Load<Parent>(1);
System.Diagnostics.Debug.WriteLine("Before modifications and commit");
System.Diagnostics.Debug.WriteLine("Parent0 number of children: " + parent0.Children.Count);
System.Diagnostics.Debug.WriteLine("Parent1 number of children: " + parent1.Children.Count);
parent0.Children[0].Parent = parent1;
transaction.Commit();
}
}
System.Diagnostics.Debug.WriteLine("After modifications and commit");
System.Diagnostics.Debug.WriteLine("Parent0 number of children: " + parent0.Children.Count);
System.Diagnostics.Debug.WriteLine("Parent1 number of children: " + parent1.Children.Count);
Entity framework test code:
System.Diagnostics.Debug.WriteLine("Test Entity Framework:");
Parent parent0, parent1;
using (Entities entities = new Entities())
{
parent0 = entities.Parents.Find(0);
parent1 = entities.Parents.Find(1);
System.Diagnostics.Debug.WriteLine("Before modifications and commit");
System.Diagnostics.Debug.WriteLine("Parent0 number of children: " + parent0.Children.Count);
System.Diagnostics.Debug.WriteLine("Parent1 number of children: " + parent1.Children.Count);
parent0.Children[0].Parent = parent1;
entities.SaveChanges();
}
System.Diagnostics.Debug.WriteLine("After modifications and commit");
System.Diagnostics.Debug.WriteLine("Parent0 number of children: " + parent0.Children.Count);
System.Diagnostics.Debug.WriteLine("Parent1 number of children: " + parent1.Children.Count);
So basically with this test I can see the counts changing with EF but not with NHibernate. Am I doing something wrong with NH or do I have to manually manage every part of the relationships affected by my changes ? Thanks!
In NHibernate you would need to manually move them from one parent collection to another. I usually use Add or Remove methods in the parent classes to do this. Here is an example of these add or remove methods:
public virtual void AddLine(OrderLine orderLine)
{
orderLine.Order = this;
this.orderLines.Add(orderLine);
}
public virtual void RemoveLine(OrderLine orderLine)
{
this.orderLines.Remove(orderLine);
}
To reparent a child I would then do something like this:
originalParent.RemoveLine(child);
newParent.AddLine(child);
When I am trying to generate Apex classes from the below WSDL file I am getting the
The following generated class(es) have compilation errors:
Error: testxyzCom
Error: unexpected token: 'limit' at 7:23
The generated class is also given below. I already have some experience in Salesforce and as far as I remember if a WSDL document contains an Apex reserved word, the word is appended with _x when the Apex class is generated. For example, limit in a WSDL document converts to limit_x in the generated Apex class. But this is not happening in above case please explain. Please help me out.
The WSDL file
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://test.xyz.com" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://test.xyz.com" xmlns:intf="http://test.xyz.com" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!--WSDL created by Apache Axis version: 1.4
Built on Apr 22, 2006 (06:55:48 PDT)-->
<wsdl:types>
<schema elementFormDefault="qualified" targetNamespace="http://test.xyz.com" xmlns="http://www.w3.org/2001/XMLSchema">
<element name="createOpurtunityData">
<complexType>
<sequence>
<element maxOccurs="unbounded" name="keys" type="xsd:string"/>
<element maxOccurs="unbounded" name="values" type="xsd:string"/>
<element name="limit" type="xsd:int"/>
</sequence>
</complexType>
</element>
<element name="createOpurtunityDataResponse">
<complexType>
<sequence>
<element maxOccurs="unbounded" name="createOpurtunityDataReturn" type="xsd:string"/>
</sequence>
</complexType>
</element>
</schema>
</wsdl:types>
<wsdl:message name="createOpurtunityDataResponse">
<wsdl:part element="impl:createOpurtunityDataResponse" name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:message name="createOpurtunityDataRequest">
<wsdl:part element="impl:createOpurtunityData" name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:portType name="TestWSDL">
<wsdl:operation name="createOpurtunityData">
<wsdl:input message="impl:createOpurtunityDataRequest" name="createOpurtunityDataRequest">
</wsdl:input>
<wsdl:output message="impl:createOpurtunityDataResponse" name="createOpurtunityDataResponse">
</wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="TestWSDLSoapBinding" type="impl:TestWSDL">
<wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="createOpurtunityData">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="createOpurtunityDataRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="createOpurtunityDataResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="TestWSDLService">
<wsdl:port binding="impl:TestWSDLSoapBinding" name="TestWSDL">
<wsdlsoap:address location="http://tempuri.org/Salesforcexyz/services/TestWSDL"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Generated Apex class is
/Generated by wsdl2apex
public class testxyzCom {
public class createOpurtunityData_element {
public String[] keys;
public String[] values;
public Integer limit;
private String[] keys_type_info = new String[]{'keys','http://www.w3.org/2001/XMLSchema','string','1','-1','false'};
private String[] values_type_info = new String[]{'values','http://www.w3.org/2001/XMLSchema','string','1','-1','false'};
private String[] limit_type_info = new String[]{'limit','http://www.w3.org/2001/XMLSchema','int','1','1','false'};
private String[] apex_schema_type_info = new String[]{'http://test.xyz.com','true','false'};
private String[] field_order_type_info = new String[]{'keys','values','limit'};
}
public class TestWSDL {
public String endpoint_x = 'http://tempuri.org/Salesforcexyz/services/TestWSDL';
public Map<String,String> inputHttpHeaders_x;
public Map<String,String> outputHttpHeaders_x;
public String clientCertName_x;
public String clientCert_x;
public String clientCertPasswd_x;
public Integer timeout_x;
private String[] ns_map_type_info = new String[]{'http://test.xyz.com', 'testxyzCom'};
public String[] createOpurtunityData(String[] keys,String[] values,Integer limit) {
testxyzCom.createOpurtunityData_element request_x = new testxyzCom.createOpurtunityData_element();
testxyzCom.createOpurtunityDataResponse_element response_x;
request_x.keys = keys;
request_x.values = values;
request_x.limit = limit;
Map<String, testxyzCom.createOpurtunityDataResponse_element> response_map_x = new Map<String, testxyzCom.createOpurtunityDataResponse_element>();
response_map_x.put('response_x', response_x);
WebServiceCallout.invoke(
this,
request_x,
response_map_x,
new String[]{endpoint_x,
'',
'http://test.xyz.com',
'createOpurtunityData',
'http://test.xyz.com',
'createOpurtunityDataResponse',
'testxyzCom.createOpurtunityDataResponse_element'}
);
response_x = response_map_x.get('response_x');
return response_x.createOpurtunityDataReturn;
}
}
public class createOpurtunityDataResponse_element {
public String[] createOpurtunityDataReturn;
private String[] createOpurtunityDataReturn_type_info = new String[]{'createOpurtunityDataReturn','http://www.w3.org/2001/XMLSchema','string','1','-1','false'};
private String[] apex_schema_type_info = new String[]{'http://test.xyz.com','true','false'};
private String[] field_order_type_info = new String[]{'createOpurtunityDataReturn'};
}
}
I've had a similar issue recently with a WSDL that generated an APEX class using the reserved keyword 'long'.
I don't think wsdl2apex is smart enough to add a suffix to reserved keywords as you suggest.
Can you do it by hand to the generated class?
In createOpurtunityData_element
public Integer limit_x;
In TestWSDL
public String[] createOpurtunityData(String[] keys,String[] values,Integer limit_x) {
request_x.limit_x = limit_x;
I'm not 100% sure how the call to WebServiceCallout.invoke will handle this change though. If you can, it would be easier to update the web service and WSDL so it doesn't use a APEX keyword.
I'm trying to enable solution-wide logging by adding a stand-alone project that wraps log4net. I found a code on StackOverflow but the code is using some config file. I do not understand that bit. Here is the only static class:
using log4net;
using log4net.Config;
using System;
using System.IO;
namespace ExciteEngine2.LoggingManager {
//// TODO: Implement the additional GetLogger method signatures and log4net.LogManager methods that are not seen below.
public static class ExciteLog {
private static readonly string LOG_CONFIG_FILE = #"log4net.config";
public static ILog GetLogger(Type type) {
// If no loggers have been created, load our own.
if (LogManager.GetCurrentLoggers().Length == 0) {
LoadConfig();
}
return LogManager.GetLogger(type);
}
private static void LoadConfig() {
//// TODO: Do exception handling for File access issues and supply sane defaults if it's unavailable.
try {
XmlConfigurator.ConfigureAndWatch(new FileInfo(LOG_CONFIG_FILE));
}
catch (Exception ex) {
}
}
}
}
Now, there is no log4net.config anywhere. And in my main application project, I'm using the ILog as follows:
using log4net;
using ExciteEngine2.LoggingManager;
namespace ExciteEngine2.MainApplication {
internal static class Program {
public static readonly ILog ApplicationLogger = ExciteLog.GetLogger(typeof(Program));
private static void SetupLogging() {
log4net.Config.XmlConfigurator.Configure();
}
[STAThread] static void Main(string[] args) {
//Uninstall
foreach (string arg in args) {
if (arg.Split('=')[0] == "/u") {
Process.Start(new ProcessStartInfo(Environment.GetFolderPath(Environment.SpecialFolder.System) + "\\msiexec.exe", "/x " + arg.Split('=')[1]));
return;
}
}
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-GB");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-GB");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
try {
ThemeResolutionService.ApplicationThemeName = ConfigurationManager.AppSettings["ThemeToUse"];
}
catch (Exception ex) {
ApplicationLogger.Error("Exception while setting Telerik Theme.", ex);
ThemeResolutionService.ApplicationThemeName = "ControlDefault";
}
DevExpress.UserSkins.OfficeSkins.Register();
DevExpress.UserSkins.BonusSkins.Register();
DevExpress.Skins.SkinManager.EnableFormSkins();
DevExpress.Skins.SkinManager.EnableMdiFormSkins();
//try {
if (args.Contains("/dx")) {
Application.Run(new AppMDIRibbonDX());
ApplicationLogger.Info("Application (DX) started.");
}
else {
Application.Run(new AppMDIRibbon());
ApplicationLogger.Info("Application started.");
}
//} catch (Exception ex) {
// ApplicationLogger.Fatal("Exception while initiating. Nothing can be done here.", ex);
// XtraMessageBox.Show(String.Format("Exception while initiating. Nothing can be done here.{0}Message: {1}", Environment.NewLine, ex.Message), "Excite Engine 2", MessageBoxButtons.OK, MessageBoxIcon.Error);
//}
}
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) {
ApplicationLogger.Fatal("Application Level Exception.", e.Exception);
Thread t = (Thread)sender;
Exception threadexception = e.Exception;
string errormessage = String.Format("Thread ID: {0} [ {1} ]", t.ManagedThreadId, threadexception.Message);
XtraMessageBox.Show(String.Format("Application Level Exception!{1}{0}{1}Details:{1}{2}", errormessage, Environment.NewLine, threadexception.StackTrace), "Excite Engine 2", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
As you can see from my flow, I'm executing this line of code thinking log4net will use my main application project's app.config: log4net.Config.XmlConfigurator.Configure();
And here is a line I added in AssemblyInfo.cs:
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
Finally, the app.config for my Main application:
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>
</configSections>
<appSettings>
</appSettings>
<connectionStrings>
</connectionStrings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
</startup>
<log4net>
<root>
<level value="DEBUG" />
<appender-ref ref="LogFileAppender" />
</root>
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender" >
<param name="File" value="Excite Engine 2 Log.log" />
<param name="AppendToFile" value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%-5p%d{ddd, dd-MMM-yyyy hh:mm:ss} - %m%n" />
</layout>
</appender>
<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender" >
<applicationName value="Excite Engine 2" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
</log4net>
</configuration>
When I run with <appender-ref ref="LogFileAppender" />, I get an empty file named Excite Engine 2 Log.log right next to my main EXE. And when I set <appender-ref ref="EventLogAppender" />, nothing happens in Event Viewer. Also, there is an attribute: <level value="DEBUG" /> thats really bothering me. What I want is a full EventViewer logging for my application regardless of the build configuration it is running in.
Appreciate if someone could guide me on this. Thanks!
I found a code on StackOverflow but
the code is using some config file. I
do not understand that bit.
The reason he's using a specific config file can be explained by the following taken from log4net's site:
The System.Configuration API is only
available if the configuration data is
in the application's config file; the
file named MyApp.exe.config or
Web.config. Because the
System.Configuration API does not
support reloading of the config file
the configuration settings cannot be
watched using the
log4net.Config.XmlConfigurator.ConfigureAndWatch
methods. The main advantage of using
the System.Configuration APIs to read
the configuration data is that it
requires less permissions than
accessing the configuration file
directly. The only way to configure an
application using the
System.Configuration APIs is to call
the
log4net.Config.XmlConfigurator.Configure()
method or the
log4net.Config.XmlConfigurator.Configure(ILoggerRepository)
method.
Edit:
To log to your log file you need to call your SetupLogging method above.
log4net.Config.XmlConfigurator.Configure();
This statement is never being called. It looks like you are calling LoadConfig() in your ExciteEngine2.LoggingManager but this uses a config file called log4net.config which you said doesn't exist. If you are putting your configuration in your app.config file then you need to call your SetupLogging method.
I am reading up more on XAML and I have created an XML file and want to load it. It all works but when I use the ContentProperty attribute and more importantly I remove the Company.Employees tags from the XML file, I get the error "cannot add to Company" when loading the xml file.
The code is :
<?xml version="1.0" encoding="utf-8" ?>
<Company Name="BBC" xmlns="clr-namespace:XamlLoading;assembly=XamlLoading">
<Company.Owner>
<Person Name="John" Age="49"/>
</Company.Owner>
<!--<Company.Employees>
<Person Name="Dave" Age="66" />
<Person Name="Paul" Age="45"/>
</Company.Employees>-->
<Person Name="Dave" Age="66" />
<Person Name="Paul" Age="45"/>
</Company>
[ContentProperty("Employees")]
public class Company
{
public Company()
{
Employees = new List<Person>();
}
public Person Owner { get; set; }
public string Name { get; set; }
public List<Person> Employees { get; set; }
}
static void Main(string[] args)
{
using (FileStream fs = File.OpenRead(#"..\..\company.xml"))
{
Company c = (Company)XamlReader.Load(fs); * ERROR HERE
Console.WriteLine(c.Name);
Console.WriteLine(c.Owner);
foreach (var item in c.Employees)
{
Console.WriteLine("{0} : ", item);
}
Console.ReadLine();
}
}
I would suggest that you update to the latest version of .NET. Your code works great for me.
This is a very interesting case study for XAML. I have never seen it used this way before. Typically XAML is used like HTML markup for declaratively defining a user interface. Blend is a WYSIWYG editor for creating user interfaces by generating XAML.
You have demonstrated some interesting potential for realizing data from xml using the XamlReader.