I'm working with a graph dataset that could have edges of different logical meaning, like that:
"Bavaria" -[PART_OF]-> "Germany"
"Germany" -[NEIGHBOR_OF]-> "France"
I represent this domain by using the QuickGraph.TaggedEdge where TTag generic parameter is a string:
QuickGraph.BidirectionalGraph<IGeographicalUnit, TaggedEdge<IGeographicalUnit, string>>
This works perfectly until the moment I try to serialize my graph to .graphml form:
using (var w = XmlWriter.Create(#"C:\Temp\data.graphml"))
{
_graph.SerializeToGraphML<IGeographicalUnit, TaggedEdge<IGeographicalUnit, string>, BidirectionalGraph<IGeographicalUnit, TaggedEdge<IGeographicalUnit, string>>>(w);
}
Serialized edge data doesn't contain any tag information, only source and target:
<edge id="0" source="0" target="1" />
What I want is something like:
<edge id="0" source="0" target="1" tag="PART_OF" />
So, the question is, how can I enforce this tag to be serialized?
To solve this problem, I created my own edge implementation pretty similar to the TaggedEdge mentioned above:
public class DataEdge<TVertex> : Edge<TVertex>
{
[XmlAttribute("Tag")]
public string Tag { get; set; }
public DataEdge(TVertex source, TVertex target)
: base(source, target) { }
public DataEdge(TVertex source, TVertex target, string tag)
: this(source, target)
{
Tag = tag;
}
}
Then I replaced TaggedEdge occurrences with my DataEdge. After that, serialization produced the following XML output:
<edge id="0" source="0" target="1">
<data key="Tag">PART_OF</data>
</edge>
The problem is solved, but I hope that another solution exists that don't involve writing your own Edge implementations.
Related
I am brand new on .net 5 asp tag helpers. I have models like these:
public class MyForm
{
public String Url { get; set; }
...
}
public class MyViewModel
{
[Required]
public String Url { get; set; }
[DisplayName("Seller username")]
[Required]
public String SellerName { get; set; }
...
}
In my controller I got and URL value for example https://myshop.com/item?id=1234
public IActionResult AddLinkWizardSecond(MyForm form)
{
var model = new MyViewModel() {
Url = "https://anotherShop.com/index.html",
SellerName = "test user 123",
};
return PartialView("myView", model);
}
Where my view looks as:
#model MyViewModel
<input asp-for="Url" readonly>
<input asp-for="SellerName">
It is said that the tag helper for input element renders all necessary tags including value tag also. Several examples (on the internet) shows that the rendered html contains <input value="...somevalue...". But - for me this is odd - the rendered html I got in my browser looks as:
<input name="Url" id="Url" value="https://myshop.com/item?id=1234" ... />
<input name="SellerName" id="SellerName" value="" ... />
There must be reason behind this - but I cant catch it. Could somebody give me some ideas why the url contains the posted data instead of the new one, and why the seller name value is empty when I fill these properties? I tried to put the values to ViewBag and ViewData before - but none of them are working:
...
this.ViewData["SellerName"] = model.SellerName;
return PartialView("myView", model);
Is this too much I ask for the tag helpers? They cannot use the current values? Then where the posted value comes from?
Apologizes for the dummy question :( Any advice is greatly welcome which can help me out from the deep swamp of despair where I am now :(
You are correct this is a design choice in the framework. You can read about why it was made, some theory, and also a few work arounds in this blog post.
For example, calling ModelState.Clear(); in your Post action will display the behavior you are looking for.
However, its standard "practice" to use the Post Redirect Pattern regardless, which solves the problem.
First of all, what is my intention. I have a set of XML files in my project. Some of those are hierarchical. The top XML looks like this (very simple example)
<RootElement>
<Element id=1>
<Element id=2>
<Element id=3>
<RootElement>
The element itself contains some other elements and attributes, but it is not relevant in this case.
Than there are many files with this structure:
<RootElement>
<Element id=1 superId=3>
<Element id=2 superId=3>
<Element id=3 superId=2>
<RootElement>
Where the superID is index to root XML file. What I want to implement is a plugin which I would use for simple navigation between those two files.
My idea was to create a new language which will extend XML and add some extra functionality. Only files with specific names (2 or 3) will be part of this language.
I have created the new language:
public class MyLanguage extends XMLLanguage {
public static final MyLanguage INSTANCE = new MyLanguage();
protected MyLanguage() {
super(XMLLanguage.INSTANCE,"MyLanguage", new String[]{"text/xml"});
}
}
New file type:
public class MyLanguageFileType extends XmlLikeFileType {
public static final MyLanguageFileType INSTANCE = new MyLanguageFileType();
protected MyLanguageFileType() {
super(MyLanguage.INSTANCE);
}
#Override
public Icon getIcon() {
return Icons.FILE;
}
And new factory:
public class MyLanguageFileFactory extends XmlFileTypeFactory {
#Override
public void createFileTypes(FileTypeConsumer fileTypeConsumer) {
fileTypeConsumer.consume(MyLanguageFileType.INSTANCE,
new FileNameMatcherFactoryImpl().createMatcher("nameOfXML1.xml"),
new FileNameMatcherFactoryImpl().createMatcher("nameOfXML2.xml")
);
}
What is the first problem? I see files with the right icon, but when I create Anotator and register it to MyLanguage, it doesn't work. When I register the same Annotator to the XML file, annotations works well.
So the first question is, what have I done wrong?
Thanks all.
P.S.: Minimally FileTypeFactory works well because I can see files with specific names with icons I have set to it.
You don't need to implement your own language to support the navigation. All you need to do is to implement a PsiReferenceContributor that will inject references into the attributes of your XML files.
Another solution if you just need code completion and static analysis is to use an <xml.schemaProvider implementation="..."> tag in your plugin.xml file with a custom XmlSchemaProvider that returns a local *.xsd file packaged with your plugin. See JavaFxSchemaProvider for an example of how to do this.
how to set attributes for soap message:
for example my soap messg look like following
<doPaymentResult xmlns:a="http://schemas.datacontract.org/2004/07/MemoService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:errors i:nil="true"/>
<a:messages>
<a:MessageEntity>
<a:codeField>Payment Request Successful</a:codeField>
<a:textField i:nil="true" xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
</a:MessageEntity>
</a:messages>
<a:requestTrackCode>20130430T125904R14646</a:requestTrackCode>
<a:status i:nil="true"/>
</doPaymentResult>
</doPaymentResponse>
but i need a soap message which take attributes not elements
like following
<doPaymentResult xmlns:a="http://schemas.datacontract.org/2004/07/MemoService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:errors i:nil="true"/>
<a:messages>
<a:MessageEntity codeField="Payment Request Successful">
some text here
</a:MessageEntity>
</a:messages>
<a:requestTrackCode>20130430T125904R14646</a:requestTrackCode>
<a:status i:nil="true"/>
</doPaymentResult>
</doPaymentResponse>
I am using datacontract in class.
It’s a common problem – you want to return an object from a WCF service as XML, but you either want, or need, to deliver some or all of the property values as XML Attributes instead of XML Elements; but you can’t because the DataContractSerializer doesn’t support attributes (you’re most likely to have seen this StackOverflow QA if you’ve done a web search). Most likely you’ve then migrated all your WCF service code to using the XmlSerializer (with all the XmlElement/XmlAttribute/XmlType attributes et al) – and you’ve cursed loudly.
Well, I’m here to rescue you, because it is possible – and the answer to the problem is actually inferred from the MSDN article entitled ‘Types supported by the Data Contract Serializer’.
The example I’m going to give is purely for illustration purposes only. I don’t have a lot of time, so work with me!
•Create a new Asp.Net WCF service application, you can use Cassini as your web server (probably easier – otherwise you might have to enable Asp.Net compatibility mode).
•Open the web.config and delete the element that was created for the new service.
•The interface and implementation model for this example is overkill. Move the [ServiceContract] and [OperationContract] declarations from the interface that was created for you new service to the class that was also created. Delete the interface.
•Open the .svc markup file and add the following at the end: Factory="System.ServiceModel.Activation.WebServiceHostFactory" – this enables the zero-configuration WCF model for this service (we’re going to create a RESTful service).
•Paste the following class declarations into your svc codebehind:
public interface IExampleData
{
string Description { get; set; }
string Name { get; set; }
int ID { get; set; }
}
public class ExampleData : IExampleData
{
public string Description { get; set; }
public string Name { get; set; }
public int ID { get; set; }
}
public class ExampleDataAttributed : ExampleData, IXmlSerializable
{
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
//implement if remote callers are going to pass your object in
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteAttributeString("id", ID.ToString());
writer.WriteAttributeString("name", Name);
//we'll keep the description as an element as it could be long.
writer.WriteElementString("description", Description);
}
#endregion
}
Just to demonstrate the point, the class that will be part-serialized to attributes simply derives from one that will be serialized as normal.
•Now add the following two methods to your service class:
[OperationContract]
[WebGet(UriTemplate = "/test1")]
public ExampleData Test1()
{
return new ExampleData() { ID = 1,
Name = "Element-centric",
Description =
"The contents of this item are entirely serialized to elements - as normal" };
}
[OperationContract]
[WebGet(UriTemplate = "/test2")]
public ExampleDataAttributed Test2()
{
return new ExampleData_Attributed() { ID = 2,
Name = "Mixed",
Description =
"Everything except this description will be serialized to attributes" };
}
Cover, and bake for 40 minutes (that is – Build it).
If you left your service as Service1.svc, then run it and open up IE and browse to http://localhost:[port of cassini]/test1
The result should look something like this:
<JSLabs.ExampleData
xmlns="http://schemas.datacontract.org/2004/07/ExampleNamespace"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Description>
The contents of this item are entirely serialized to elements - as normal
</Description>
<ID>
1
</ID>
<Name>
Element-centric
</Name>
</JSLabs.ExampleData>
Now browse to http://localhost:[port of cassini]/test2
<JSLabs.ExampleDataAttributed id="2" name="Mixed"
xmlns="http://schemas.datacontract.org/2004/07/JobServe.Labs.Web">
<description>Everything except this description will be
serialized to attributes</description>
</JSLabs.ExampleDataAttributed>
It’s made a little less impressive by that nasty ‘orrible “xmlns=” attribute that the WCF data contract serializer automatically puts on the type – but, as you can see, the ‘ID’ and ‘Name’ properties have indeed been pushed out as attributes!
We could have made both methods return IExampleData and then used the KnownType attribute on that interface in order to get it to support either (according to what the code of the methods returned).
To support deserializing an object from the attributes, all you have to do is to implement the IXmlSerializable.ReadXml method.
Finally, as the aforementioned MSDN article says about the supported types – you should also be able to use XmlElement/XmlNode types as a way of representing XML directly – the DataContractSerializer, like in this case, take the short route and simply gets the Xml.
This also shouldn’t affect JSON formatting if you’re dual-outputting objects for either XML or JSON clients.
Check the source of this article
I just had a NHibernate related problem where I forgot to map one property of a class.
A very simplified example:
public class MyClass
{
public virtual int ID { get; set; }
public virtual string SomeText { get; set; }
public virtual int SomeNumber { get; set; }
}
...and the mapping file:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="MyAssembly"
namespace="MyAssembly.MyNamespace">
<class name="MyClass" table="SomeTable">
<property name="ID" />
<property name="SomeText" />
</class>
</hibernate-mapping>
In this simple example, you can see the problem at once:
there is a property named "SomeNumber" in the class, but not in the mapping file.
So NHibernate will not map it and it will always be zero.
The real class had a lot more properties, so the problem was not as easy to see and it took me quite some time to figure out why SomeNumber always returned zero even though I was 100% sure that the value in the database was != zero.
So, here is my question:
Is there some simple way to find this out via NHibernate?
Like a compiler warning when a class is mapped, but some of its properties are not.
Or some query that I can run that shows me unmapped properties in mapped classes...you get the idea.
(Plus, it would be nice if I could exclude some legacy columns that I really don't want mapped.)
EDIT:
Okay, I looked at everything you proposed and decided to go with the meta-data API...that looks the easiest to understand for me.
Now that I know what to search for, I found some examples which helped me to get started.
So far, I have this:
Type type = typeof(MyClass);
IClassMetadata meta = MySessionFactory.GetClassMetadata(type);
PropertyInfo[] infos = type.GetProperties();
foreach (PropertyInfo info in infos)
{
if (meta.PropertyNames.Contains(info.Name))
{
Console.WriteLine("{0} is mapped!", info.Name);
}
else
{
Console.WriteLine("{0} is not mapped!", info.Name);
}
}
It nearly works, except one thing:
IClassMetadata.PropertyNames returns the names of all the properties except the ID.
To get the ID, I have to use IClassMetadata.IdentifierPropertyName.
Yes, I could save .PropertyNames in a new array, add .IdentifierPropertyName to it and search that array.
But this looks strange to me.
Is there no better way to get all mapped properties including the ID?
You could use the NHibernate meta-data API to find the mapped properties, and reflection to find all the properties.
Edit No, there isn't any other way list all the properties including the id. It isn't that hard to use:
foreach (PropertyInfo info in infos)
{
if (meta.PropertyNames.Contains(info.Name) || info.Name = meta.IdentifierPropertyName)
{
Console.WriteLine("{0} is mapped!", info.Name);
}
else
{
Console.WriteLine("{0} is not mapped!", info.Name);
}
}
There are two tools I'm aware of that can help with this:
Fluent NHibernate persistence specification testing
Nhibernate Ghostbuster
but they don't specifically address the problem you had with an unmapped property. The best solution is to write good unit tests that ensure that the properties you want to persist are persisted correctly. It's tedious but necessary.
My "Location" object isnt getting serialized in my WCF datacontract, however, all other variables are being set properly. When I try to output a variable in the location object I get the "Object reference not set to an instance of an object" error
My DataContract:
[DataContract(Namespace = "")]
public class CalcRequest : BaseRequest
{
[DataMember(Name = "Products")]
public List<Product> products;
[DataMember(Name = "Location")]
public Location location;
[DataMember(Name = "ShippingMethod")]
public string shippingMethod;
[DataMember(Name = "SystemPromotionCode")]
public string systemPromotionCode;
[DataMember(Name = "UserPromotionCode")]
public string userPromotionCode;
}
The "Location" object:
[DataContract(Name = "Location", Namespace = "")]
public class Location
{
public Location()
{
// do nothing
}
[DataMember(Name = "Country")]
public string country;
[DataMember(Name = "StateProvince")]
public string stateProvince;
[DataMember(Name = "PostalCode")]
public string postalCode;
}
my XML request (version, msgtype, processorID, and customerid are in my "BaseRequest"):
<root>
<Version>1.0</Version>
<MsgType>type</MsgType>
<ProcessorId>28000</ProcessorId>
<CustomerId>28000</CustomerId>
<Products>
<Product>
<SKU>1</SKU>
<Price>2999</Price>
<ProductName>name1</ProductName>
<Quantity>1</Quantity>
</Product>
<Product>
<SKU>2</SKU>
<Price>1999</Price>
<ProductName>name2</ProductName>
<Quantity>1</Quantity>
</Product>
</Products>
<Location>
<Country>US</Country>
<StateProvince>OH</StateProvince>
<PostalCode>44060</PostalCode>
</Location>
<ShippingMethod>USPS-NextDay</ShippingMethod>
<SystemPromotionCode>CD1244578</SystemPromotionCode>
<UserPromotionCode>2FDGRR</UserPromotionCode>
</root>
... Not sure why this isn't working... any help would be appreciated.
I don't understand what you think is missing, really....
(stuff deleted - not relevant)
UPDATE: to make sure the order of the elements in the XML is correct and interpreted in the right order, you might want to add Order=xxx statement to the data member attributes-
Otherwise, the data contract serializer will serialize (and deserialize) in alphabetical order (other than the XmlSerializer which serializes in the order the fields appear).
Alphabetical order is case-sensitive,i.e. any upper case characters are considered before any low-case characters.
If you have multiple elements of the same order (that's not a problem), then they'll be serialized alphabetically within their order (e.g. all elements of Order=1 will be serialized in an alphabetical fashion - then all elements with Order=2 and so on).
For derived classes, properties of base class will be serialized first(in alphabetical order) and properties of derived class later(also in alphabetical order).