I'm trying to configure Security Token Service using WCF so it could create tokens (SessionSecurityToken) using WSSecureConversationFebruary2005 namespace. SessionSecurityToken class has property SecureConversationVersion which in theory can be set to my desired value. Unfortunately by default it is not and I don't see a way to change it. After analysing source code I noticed that there is constructor which can change this value but it is internal.
http://msdn.microsoft.com/pl-pl/library/system.identitymodel.tokens.sessionsecuritytoken.secureconversationversion%28v=vs.110%29.aspx
Code I use for hosting STS looks like:
BindingElementCollection bindings = new BindingElementCollection();
SecurityBindingElement security = SecurityBindingElement.CreateUserNameOverTransportBindingElement();
security.AllowInsecureTransport = true;
security.EnableUnsecuredResponse = true;
security.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;
bindings.Add(security);
TextMessageEncodingBindingElement textMessageEncoding = new TextMessageEncodingBindingElement();
bindings.Add(textMessageEncoding);
textMessageEncoding.MessageVersion = MessageVersion.Soap11WSAddressingAugust2004;
HttpTransportBindingElement httpsTransport = new HttpTransportBindingElement();
bindings.Add(httpsTransport);
var myBinding = new CustomBinding(bindings);
var host = new WSTrustServiceHost(Configuration, new Uri(BaseAddress));
host.AddServiceEndpoint(
typeof(IWSTrustFeb2005SyncContract),
myBinding,
STS_ADDRESS);
The example response looks like:
<t:RequestedSecurityToken>
<SecurityContextToken d6p1:Id="_6d497e66-9851-4b74-bf6d-e5f46c652837-35820CA1B23B6109FC1DC2F6A0D3ACC3"
xmlns:d6p1="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512">
<Identifier>urn:uuid:b067f4fc-0adc-4e78-98a5-449c6b58c234</Identifier>
<Cookie xmlns="http://schemas.microsoft.com/ws/2006/05/security"></Cookie>
</SecurityContextToken>
</t:RequestedSecurityToken>
But instead of docs.oasis-open.org/ws-sx/ws-secureconversation/200512 I expect schemas.xmlsoap.org/ws/2005/02/sc
Finally I was able to achieve my goal by creating custom token handler that overrides WriteToken method. The implementation is a slightly modified version from base class and looks like this:
public class MyTokenHandler : SessionSecurityTokenHandler
{
public override void WriteToken(XmlWriter writer, SecurityToken token)
{
SessionSecurityToken sessionSecurityToken = token as SessionSecurityToken;
sessionSecurityToken.IsReferenceMode = true;
string ns = "http://schemas.xmlsoap.org/ws/2005/02/sc";
string localName = "SecurityContextToken";
string localName2 = "Identifier";
XmlDictionaryWriter xmlDictionaryWriter;
if (writer is XmlDictionaryWriter)
{
xmlDictionaryWriter = (XmlDictionaryWriter)writer;
}
else
{
xmlDictionaryWriter = XmlDictionaryWriter.CreateDictionaryWriter(writer);
}
xmlDictionaryWriter.WriteStartElement(localName, ns);
xmlDictionaryWriter.WriteElementString(localName2, ns, sessionSecurityToken.ContextId.ToString());
xmlDictionaryWriter.WriteEndElement();
xmlDictionaryWriter.Flush();
}
}
Probably this is not most elegant solution but I couldn't find better.
Related
I am creating a designer surface and loading the controls to a runtime.
I am having issues when deserializing/loading the controls to the runtime.
All methods I have tried seem to have some type of issue.
Issued faced for example:
Controls are still bound of the design-time
Not all properties deserialize with all the properties, namely nested properties.
Control associations does seem to be followed, i.e. Button in a Panel, will not be in the panel anymore, even though the property is still the parent after loading.
I have created a sample Project on git here: Surface Designer Test
There are the main code snippets:
Serialization from the design-time
private void LoadRuntime(int type)
{
var controls = surface.ComponentContainer.Components;
SerializationStore data = (SerializationStore)surface.
_designerSerializationService.Serialize(controls);
MemoryStream ms = new MemoryStream();
data.Save(ms);
SaveData.Data = ms.ToArray();
SaveData.LoadType = type;
new RuntimeForm().Show();
}
public object Serialize(System.Collections.ICollection objects)
{
ComponentSerializationService componentSerializationService =
_serviceProvider.GetService(typeof(ComponentSerializationService)) as
ComponentSerializationService;
SerializationStore returnObject = null;
using (SerializationStore serializationStore =
componentSerializationService.CreateStore())
{
foreach (object obj in objects)
{
if (obj is Control control)
{
componentSerializationService.SerializeAbsolute(serializationStore, obj);
}
returnObject = serializationStore;
}
}
return returnObject;
}
Deserialization in runtime
Here is attempt with reflection:
MemoryStream ms = new MemoryStream(SaveData.Data);
Designer d = new Designer();
var controls = d._designerSerializationService.Deserialize(ms);
ms.Close();
if (SaveData.LoadType == 1)
{
foreach (Control cont in controls)
{
var ts = Assembly.Load(cont.GetType().Assembly.FullName);
var o = ts.GetType(cont.GetType().FullName);
Control controlform = (Control)Activator.CreateInstance(o);
PropertyInfo[] controlProperties = cont.GetType().GetProperties();
foreach (PropertyInfo propInfo in controlProperties)
{
if (propInfo.CanWrite)
{
if (propInfo.Name != "Site" && propInfo.Name != WindowTarget")
{
try
{
var obj = propInfo.GetValue(cont, null);
propInfo.SetValue(controlform, obj, null);
}
catch { }
}
else { }
}
}
Controls.Add(controlform);
}
}
Here is attempt with loading controls directly (still bound to the design-time):
MemoryStream ms = new MemoryStream(SaveData.Data);
Designer d = new Designer();
var controls = d._designerSerializationService.Deserialize(ms);
foreach (Control cont in controls)
Controls.Add(cont);
I feel like I am missing a concept from the System.ComponentModel.Design framework.
I also do not believe there is a need to write a custom serializer for each control, as surely the already have this has Visual Studio is able to serialize all their properties as they are changed in the PropertyGrid and load them back when you run the program.
I'd love to serialize the designer into a .cs file, but how? How do you serialize controls/form and changed properties to a file like the VS designer, I tried and looked only to find xml and binary serializer. My ideal solution would be build a designer.cs with the CodeDom.
What is the correct way do accomplish this serialization between design-time and run-time?
Assuming you have a DesignSurface to show a Form as root component of the designer and having some components created at run-time by using CreateComponent method of IDesignerHost, here is how I approach the problem:
Get an instance of IDesignerHost from DesignSurface
Create new DesignerSerializationManager
Get an instance of TypeCodeDomSerializer from serialization manager
Serialize the RootComponent of the IDesignerHost
Create an instance of CSharpCodeProvider
Generate code by calling GenerateCodeFromType and passing the serialized root component.
You can also extend the example a bit and use ISelectionService to get notified about selected components and change properties at run-time using a PropertyGrid:
Example - Generate C# code from DesignSurface at runtime
Here in this example, I'll show how you can host a windows forms designer at run-time and design a form containing some controls and components and generate C# code at run-time and run the generated code.
Please note: It's not a production code and it's just an example as a
proof of concept.
Create the DesignSurface and host the designer
You can create the design surface like this:
DesignSurface designSurface;
private void Form1_Load(object sender, EventArgs e)
{
designSurface = new DesignSurface(typeof(Form));
var host = (IDesignerHost)designSurface.GetService(typeof(IDesignerHost));
var root = (Form)host.RootComponent;
TypeDescriptor.GetProperties(root)["Name"].SetValue(root, "Form1");
root.Text = "Form1";
var button1 = (Button)host.CreateComponent(typeof(Button), "button1");
button1.Text = "button1";
button1.Location = new Point(8, 8);
root.Controls.Add(button1);
var timer1 = (Timer)host.CreateComponent(typeof(Timer), "timer1");
timer1.Interval = 2000;
var view = (Control)designSurface.View;
view.Dock = DockStyle.Fill;
view.BackColor = Color.White;
this.Controls.Add(view);
}
Generate C# code using TypeCodeDomSerializer and CSharpCodeProvider
This is how I generate code from design surface:
string GenerateCSFromDesigner(DesignSurface designSurface)
{
CodeTypeDeclaration type;
var host = (IDesignerHost)designSurface.GetService(typeof(IDesignerHost));
var root = host.RootComponent;
var manager = new DesignerSerializationManager(host);
using (manager.CreateSession())
{
var serializer = (TypeCodeDomSerializer)manager.GetSerializer(root.GetType(),
typeof(TypeCodeDomSerializer));
type = serializer.Serialize(manager, root, host.Container.Components);
type.IsPartial = true;
type.Members.OfType<CodeConstructor>()
.FirstOrDefault().Attributes = MemberAttributes.Public;
}
var builder = new StringBuilder();
CodeGeneratorOptions option = new CodeGeneratorOptions();
option.BracingStyle = "C";
option.BlankLinesBetweenMembers = false;
using (var writer = new StringWriter(builder, CultureInfo.InvariantCulture))
{
using (var codeDomProvider = new CSharpCodeProvider())
{
codeDomProvider.GenerateCodeFromType(type, writer, option);
}
return builder.ToString();
}
}
For example:
var code = GenerateCSFromDesigner(designSurface);
Run the code sing CSharpCodeProvider
Then to run it:
void Run(string code, string formName)
{
var csc = new CSharpCodeProvider();
var parameters = new CompilerParameters(new[] {
"mscorlib.dll",
"System.Windows.Forms.dll",
"System.dll",
"System.Drawing.dll",
"System.Core.dll",
"Microsoft.CSharp.dll"});
parameters.GenerateExecutable = true;
code = $#"
{code}
public class Program
{{
[System.STAThread]
static void Main()
{{
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
System.Windows.Forms.Application.Run(new {formName}());
}}
}}";
var results = csc.CompileAssemblyFromSource(parameters, code);
if (!results.Errors.HasErrors)
{
System.Diagnostics.Process.Start(results.CompiledAssembly.CodeBase);
}
else
{
var errors = string.Join(Environment.NewLine,
results.Errors.Cast<CompilerError>().Select(x => x.ErrorText));
MessageBox.Show(errors);
}
}
For example:
Run(GenerateCSFromDesigner(designSurface), "Form1");
I have implemented my XmlTextReader with overridden setting for CheckCharacters. Something like this:
class MyXmlTextReader : XmlTextReader
{
public MyXmlTextReader(TextReader input) : base(input)
{
}
/// <summary>
/// Settings
/// </summary>
public override XmlReaderSettings Settings
{
get { return new XmlReaderSettings { CheckCharacters = false }; }
}
}
When I use it in normal scenario with invalid xml data everything works fine:
var sr3 = new StringReader(xml);
var xr3 = new MyXmlTextReader(sr3);
var obj3 = (MyObject)ser.Deserialize(xr3);
But as soon as I turn on normalisation, I start getting InvalidCharacter exceptions:
var sr3 = new StringReader(xml);
var xr3 = new MyXmlTextReader(sr3);
xr3.Normalization = true;
var obj3 = (MyObject)ser.Deserialize(xr3);
Is there a way to have normalisation, but at the same time ignore invalid xml characters?
Here is a sample application to reproduce the problem:
https://gist.github.com/ncksol/29bd6490edd0580c25f7338b417b37d3
This appears to be a shortcoming in the implementation:
XmlReader has no Normalization property.
XmlReader.Create allows you to pass CheckCharacters as a setting, but since it returns XmlReader, you can't control the normalization through it.
XmlTextReader (actually wrapping XmlTextReaderImpl) has Normalization, but no public CheckCharacters property, and no way of accepting XmlReaderSettings.
Finally, XmlTextReaderImpl, which does all the real work, can do both normalization and omitted character checking, but due to all of the above, there is no public path to configuring it that way.
If you don't mind relying on the implementation in this case, it can be done through reflection:
var sr3 = new StringReader(xml);
var xr3 = XmlReader.Create(sr3, new XmlReaderSettings { CheckCharacters = false });
// xr3.Normalization is not accessible
xr3.GetType()
.GetProperty("Normalization", BindingFlags.Instance | BindingFlags.NonPublic)
.SetValue(xr3, true);
var obj3 = (MyObject)ser.Deserialize(xr3);
Hacky, but still far preferable over implementing XmlTextReader from scratch which, given all the cleverness in the implementation, is not something to undertake lightly.
Note that XmlReader.Create is not contractually obligated to return an instance of a type that has a Normalization property, it just happens to do so in the current implementation.
In my ElasticSearch server, I have an existing index template, which contains some settings and some mappings.
I want to add a mapping for a new type to the template, but since it's not possible to update templates, I need to delete the existing one and recreate it.
Since I would like to keep all the existing settings, I tried getting the existing definition, add the mapping to it and then delete/recreate, like in this example:
using Nest;
using System;
public class SomeNewType {
[ElasticProperty(Index = FieldIndexOption.NotAnalyzed)]
public string SomeField { get; set; }
[ElasticProperty(Index = FieldIndexOption.Analyzed)]
public string AnotherField { get; set; }
}
class Program {
static void Main(string[] args) {
var settings = new ConnectionSettings(uri: new Uri("http://localhost:9200/"));
var client = new ElasticClient(settings);
var templateResponse = client.GetTemplate("sometemplate");
var template = templateResponse.TemplateMapping;
client.DeleteTemplate("sometemplate");
// Add a mapping to the template somehow...
template.Mappings.Add( ... );
var putTemplateRequest = new PutTemplateRequest("sometemplate") {
TemplateMapping = template
};
client.PutTemplate(putTemplateRequest);
}
}
However, I cannot find a way to add a mapping to the template definition using the ElasticProperty attributes, like in
client.Map<SomeNewType>(m => m.MapFromAttributes());
Is it possible to create a RootObjectMapping to add to the Mappings collection with something similar to MapFromAttributes?
You can do this by using the more robust PutMappingDescriptor to get a new RootObjectMapping, then add that into the collection returned by your GET _template request, like so:
var settings = new ConnectionSettings(uri: new Uri("http://localhost:9200/"));
var client = new ElasticClient(settings);
var templateResponse = client.GetTemplate("sometemplate");
var template = templateResponse.TemplateMapping;
// Don't delete, this way other settings will stay intact and the PUT will override ONLY the mappings.
// client.DeleteTemplate("sometemplate");
// Add a mapping to the template like this...
PutMappingDescriptor<SomeNewType> mapper = new PutMappingDescriptor<SomeNewType>(settings);
mapper.MapFromAttributes();
RootObjectMapping newmap = ((IPutMappingRequest) mapper).Mapping;
TypeNameResolver r = new TypeNameResolver(settings);
string mappingName = r.GetTypeNameFor(typeof(SomeNewType));
template.Mappings.Add(mappingName, newmap);
var putTemplateRequest = new PutTemplateRequest("sometemplate")
{
TemplateMapping = template
};
var result = client.PutTemplate(putTemplateRequest);
Note: TypeNameResolver is in the Nest.Resolvers namespace
As noted in the comment above, I recommend that you NOT delete the old template if the mappings are the only thing that needs updated, otherwise you will need to copy all of the other relevant settings into your new request.
I am working with a legacy application that does not import abbreviated empty xml elements. For example:
BAD empty:
<foo />
GOOD empty:
<foo></foo>
I know the solution to achieve this, which I will present now:
public class XmlTextWriterFull : XmlTextWriter
{
public XmlTextWriterFull(Stream stream, Encoding enc) : base(stream, enc)
{
}
public XmlTextWriterFull(String str, Encoding enc) : base(str, enc)
{
}
public override void WriteEndElement()
{
base.WriteFullEndElement();
}
}
and the client code:
var x_settings = new XmlWriterSettings();
x_settings.NewLineChars = Environment.NewLine;
x_settings.NewLineOnAttributes = true;
x_settings.NewLineHandling = NewLineHandling.Replace;
x_settings.CloseOutput = true;
x_settings.Indent = true;
x_settings.NewLineOnAttributes = true;
//var memOut = new MemoryStream();
var writer = new XmlTextWriterFull(outputFilename, Encoding.UTF8); //Or the encoding of your choice
var x_serial = new XmlSerializer(typeof(YOUR_OBJECT_TYPE));
x_serial.Serialize(writer, YOUR_OBJECT_INSTANCE);
writer.Close();
However, if you observed carefully the XmlWriterSettings are never used in the client code. Therefore the xml output is terribly formatted. My questions is this: how do I adapt the above code to accept XmlWriterSettings?
The use of factory creation methods and sealed/internal/abstract classes makes this difficult to implement an override.
I will accept an alternative solution, I am not married to my above solution.
WORKAROUND SOLUTION
Step 1: create the following class in your solution:
public class XmlTextWriterFull : XmlTextWriter
{
public XmlTextWriterFull(TextWriter sink) : base(sink)
{
Formatting = Formatting.Indented;
}
public override void WriteEndElement()
{
base.WriteFullEndElement();
}
}
Step 2: Add the following client code. Make sure to replace YOUR_OBJECT_TYPE and YOUR_OBJECT_INSTANCE with the class and instance your are working with:
TextWriter streamWriter = new StreamWriter(outputFilename);
var writer = new XmlTextWriterFull(streamWriter);
var x_serial = new XmlSerializer(typeof (YOUR_OBJECT_TYPE));
x_serial.Serialize(writer, YOUR_OBJECT_INSTANCE);
writer.Close();
The workaround above will produce the following empty xml element formatting:
<foo>
</foo>
The issue with this workaround is that it adds a line feed (notice the elements are on separate lines). This may be acceptable for you but causes issues with my legacy application.
How about this.
Grab the awesome XmlWrappingWriter class from http://www.tkachenko.com/blog/archives/000585.html (I have omitted the code for the sake of brevity).
With that, we can create a sub-class as follows (very similar to your original one):
public class XmlTextWriterFull2 : XmlWrappingWriter
{
public XmlTextWriterFull2(XmlWriter baseWriter)
: base(baseWriter)
{
}
public override void WriteEndElement()
{
base.WriteFullEndElement();
}
}
It can then be invoked like this (again very similar):
var x_settings = new XmlWriterSettings();
x_settings.NewLineChars = Environment.NewLine;
x_settings.NewLineOnAttributes = true;
x_settings.NewLineHandling = NewLineHandling.None;
x_settings.CloseOutput = true;
x_settings.Indent = true;
x_settings.NewLineOnAttributes = true;
using (XmlWriter writer = XmlWriter.Create(outputFilename, x_settings))
{
using (XmlTextWriterFull2 xmlTextWriterFull = new XmlTextWriterFull2(writer))
{
var x_serial = new XmlSerializer(typeof(YOUR_OBJECT_TYPE));
x_serial.Serialize(xmlTextWriterFull, YOUR_OBJECT_INSTANCE);
}
}
In my case, an element that had previously been rendered as
<Foo>
</Foo>
became
<Foo></Foo>
As you alluded to in your question, this is actually quite a tricky problem due to everything being sealed/internal etc., making overrides rather difficult. I think my biggest problem was trying to get an XmlWriter to accept XmlWriterSettings: beyond this approach, I could find no way of getting the original XmlTextWriterFull to respect the given XmlWriterSettings.
MSDN states that this method:
XmlWriter.Create(XmlWriter, XmlWriterSettings)
Can be used to apply the XmlWriterSettings to the XmlWriter. I couldn't get this to work like I wanted (the indentation never worked, for example), and upon decompiling the code, it does not appear that all the settings are used with this particular method, hence why my invocation code just passes in the outputFile (a stream of some sort would work just as well).
The workaround solution you gave in your question adds extra line breaks (when indenting is enabled) because we're telling the writer to treat this element as if it had children.
Here is how I modified your workaround to manipulate the indenting dynamically so as to avoid those extra line breaks.
public class XmlTextWriterFull : XmlTextWriter
{
public XmlTextWriterFull(TextWriter sink)
: base(sink)
{
Formatting = Formatting.Indented;
}
private bool inElement = false;
public override void WriteStartElement(string prefix, string localName, string ns)
{
base.WriteStartElement(prefix, localName, ns);
// Remember that we're in the process of defining an element.
// As soon as a child element is closed, this flag won't be true anymore and we'll know to avoid messing with the indenting.
this.inElement = true;
}
public override void WriteEndElement()
{
if (!this.inElement)
{
// The element being closed has child elements, so we should just let the writer use it's default behavior.
base.WriteEndElement();
}
else
{
// It looks like the element doesn't have children, and we want to avoid emitting a self-closing tag.
// First, let's temporarily disable any indenting, then force the full closing element tag.
var prevFormat = this.Formatting;
this.Formatting = Formatting.None;
base.WriteFullEndElement();
this.Formatting = prevFormat;
this.inElement = false;
}
}
}
Following code snippet force printing of closing tag on the same line (sorry for vb version, it should be easy to rewrite the same using C#):
Imports System.Xml
Imports System.IO
Public Class CustomXmlTextWriter
Inherits XmlTextWriter
Public Sub New(ByRef baseWriter As TextWriter)
MyBase.New(baseWriter)
Formatting = Xml.Formatting.Indented
End Sub
Public Overrides Sub WriteEndElement()
If Not (Me.WriteState = Xml.WriteState.Element) Then
MyBase.WriteEndElement()
Else
Formatting = Xml.Formatting.None
MyBase.WriteFullEndElement()
Formatting = Xml.Formatting.Indented
End If
End Sub
End Class
Another option.
public class XmlCustomTextWriter : XmlTextWriter
{
private TextWriter _tw = null;
public XmlCustomTextWriter(TextWriter sink)
: base(sink)
{
_tw = sink;
Formatting = Formatting.Indented;
Indentation = 0;
}
public void OutputElement(string name, string value)
{
WriteStartElement(name);
string nl = _tw.NewLine;
_tw.NewLine = "";
WriteString(value);
WriteFullEndElement();
_tw.NewLine = nl;
}
}
Leaving this here in case someone needs it; since none of the answers above solved it for me, or seemed like overkill.
FileStream fs = new FileStream("file.xml", FileMode.Create);
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
XmlWriter w = XmlWriter.Create(fs, settings);
w.WriteStartDocument();
w.WriteStartElement("tag1");
w.WriteStartElement("tag2");
w.WriteAttributeString("attr1", "val1");
w.WriteAttributeString("attr2", "val2");
w.WriteFullEndElement();
w.WriteEndElement();
w.WriteEndDocument();
w.Flush();
fs.Close();
The trick was to set the XmlWriterSettings.Indent = true and add it to the XmlWriter.
Edit:
Alternatively you can also use
w.Formatting = Formatting.Indented;
instead of adding an XmlWriterSettings.
I'm trying to deserialize an iCal file and then map the collection to a custom POCO. The problem is that I'm not sure where the properties are stored.
Here's the Deserialization method
public static IICalendarCollection Deserialize(String iCalUri)
{
var wc = new WebClient();
var result = wc.DownloadString(iCalUri);
using (var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(result)))
{
var serializer = new iCalendarSerializer();
var collection = (iCalendarCollection)serializer.Deserialize(memoryStream, Encoding.UTF8);
return collection;
}
}
Then in my service, I'm trying to map the properties to my POCO, but I can't find the properties.
var url = string.Format(GoogleICalUrl, calendarID);
var feed = iCalUtility.Deserialize(url);
foreach(var e in feed)
{
calendarModel.title = e.WhereTheHellAreThePropertiesKept;
}
Does anyone know the right way to loop through the iCalendarCollection and get all the properties?
I checked the DDay website but it's been down all day.
After some digging, it turns out that IICalendarCollection has a nested Event collection that needs to be parsed as follows.
var url = string.Format(GoogleICalUrl, calendarID);
var feed = iCalUtility.Deserialize(url);
foreach (var ev in feed.SelectMany(e => e.Events))
{
calendarModel.Add(new CalendarModel {description = ev.Description,
title = ev.Summary});
}