Ninject Conventions with Ninject Factory Extension To Bind Multiple Types To One Interface - inversion-of-control

I'm trying to expand on the scenario asked in the SO question titled Ninject Factory Extension Bind Multiple Concrete Types To One Interface by using Ninject Conventions for convention-based binding of the ICar implementations.
I'm working off the accepted answer authored by Akim and his Gist outlining the full example.
The difference is that I've replaced the explicit ICar bindings with convention-based bindings (or an attempt at it, at least ;)
public class CarModule : NinjectModule
{
public override void Load()
{
Bind<ICarFactory>()
.ToFactory(() => new UseFirstArgumentAsNameInstanceProvider());
// my unsuccessful binding
Kernel.Bind(scanner => scanner
.FromThisAssembly()
.SelectAllClasses()
.InheritedFrom<ICar>()
.BindAllInterfaces());
//Bind<ICar>()
// .To<Mercedes>()
// .Named("Mercedes");
//Bind<ICar>()
// .To<Ferrari>()
// .Named("Ferrari");
}
}
When I attempt to instantiate the car variable in the test, I get an ActivationException:
Ninject.ActivationException was unhandled by user code
Message=Error activating ICar
No matching bindings are available, and the type is not self-bindable.
Activation path:
1) Request for ICar
Suggestions:
1) Ensure that you have defined a binding for ICar.
2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
3) Ensure you have not accidentally created more than one kernel.
4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
5) If you are using automatic module loading, ensure the search path and filters are correct.
Source=Ninject
StackTrace:
at Ninject.KernelBase.Resolve(IRequest request) in c:\Projects\Ninject\ninject\src\Ninject\KernelBase.cs:line 362
at Ninject.ResolutionExtensions.GetResolutionIterator(IResolutionRoot root, Type service, Func`2 constraint, IEnumerable`1 parameters, Boolean isOptional, Boolean isUnique) in c:\Projects\Ninject\ninject\src\Ninject\Syntax\ResolutionExtensions.cs:line 263
at Ninject.ResolutionExtensions.Get(IResolutionRoot root, Type service, String name, IParameter[] parameters) in c:\Projects\Ninject\ninject\src\Ninject\Syntax\ResolutionExtensions.cs:line 164
at Ninject.Extensions.Factory.Factory.InstanceResolver.Get(Type type, String name, Func`2 constraint, ConstructorArgument[] constructorArguments, Boolean fallback) in c:\Projects\Ninject\ninject.extensions.factory\src\Ninject.Extensions.Factory\Factory\InstanceResolver.cs:line 75
at Ninject.Extensions.Factory.StandardInstanceProvider.GetInstance(IInstanceResolver instanceResolver, MethodInfo methodInfo, Object[] arguments) in c:\Projects\Ninject\ninject.extensions.factory\src\Ninject.Extensions.Factory\Factory\StandardInstanceProvider.cs:line 78
at Ninject.Extensions.Factory.FactoryInterceptor.Intercept(IInvocation invocation) in c:\Projects\Ninject\ninject.extensions.factory\src\Ninject.Extensions.Factory\Factory\FactoryInterceptor.cs:line 57
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.ICarFactoryProxy.CreateCar(String carType)
at Ninject.Extensions.Conventions.Tests.NinjectFactoryTests.A_Car_Factory_Creates_A_Car_Whose_Type_Name_Equals_Factory_Method_String_Argument() in C:\Programming\Ninject.Extensions.Conventions.Tests\NinjectFactoryTests.cs:line 33
InnerException:
How can I get this test to pass?
[Fact]
public void A_Car_Factory_Creates_A_Car_Whose_Type_Name_Equals_Factory_Method_String_Argument()
{
// auto-module loading is picking up my CarModule - otherwise, use:
// using (StandardKernel kernel = new StandardKernel(new CarModule()))
using (StandardKernel kernel = new StandardKernel())
{
// arrange
string carTypeArgument = "Mercedes";
ICarFactory factory = kernel.Get<ICarFactory>();
// act
var car = factory.CreateCar(carTypeArgument);
// assert
Assert.Equal(carTypeArgument, car.GetType().Name);
}
}
Here's the rest of the code, as condensed as possible, so that you don't have to refer to the original question
public interface ICarFactory { ICar CreateCar(string carType); }
public interface ICar { void Drive(); void Stop(); }
public class Mercedes : ICar {
public void Drive() { /* mercedes drives */ }
public void Stop() { /* mercedes stops */ }
}
public class Ferrari : ICar {
public void Drive() { /* ferrari drives */ }
public void Stop() { /* ferrari stops */ }
}
public class UseFirstArgumentAsNameInstanceProvider : StandardInstanceProvider
{
protected override string GetName(MethodInfo methodInfo, object[] arguments)
{
return (string) arguments[0];
}
protected override ConstructorArgument[] GetConstructorArguments(MethodInfo methodInfo, object[] arguments)
{
return base.GetConstructorArguments(methodInfo, arguments).Skip(1).ToArray();
}
}

Looks like, you have to define binding differently and provide your custom implementation of IBindingGenerator for this case
Binding
All implementation of ICar will have custom binding
Kernel.Bind(scanner => scanner
.FromThisAssembly()
.SelectAllClasses()
.InheritedFrom<ICar>()
.BindWith(new BaseTypeBindingGenerator<ICar>()));
Custom IBindingGenerator implementation
Searching for all implementations of interface and bind them by type name
public class BaseTypeBindingGenerator<InterfaceType> : IBindingGenerator
{
public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
{
if (type != null && !type.IsAbstract && type.IsClass && typeof(InterfaceType).IsAssignableFrom(type))
{
yield return bindingRoot.Bind(typeof(InterfaceType))
.To(type)
.Named(type.Name) as IBindingWhenInNamedWithOrOnSyntax<object>;
}
}
ps: here is a full sample

Related

How to override installed mappings of Behavior?

In java-9 Skins made it into public scope, while Behaviors are left in the dark - nevertheless changed considerably, in now using InputMap for all input bindings.
CellBehaviorBase installs mouse bindings like:
InputMap.MouseMapping pressedMapping, releasedMapping;
addDefaultMapping(
pressedMapping = new InputMap.MouseMapping(MouseEvent.MOUSE_PRESSED, this::mousePressed),
releasedMapping = new InputMap.MouseMapping(MouseEvent.MOUSE_RELEASED, this::mouseReleased),
new InputMap.MouseMapping(MouseEvent.MOUSE_DRAGGED, this::mouseDragged)
);
A concrete XXSkin now installs the behavior privately:
final private BehaviorBase behavior;
public TableCellSkin(TableCell control) {
super(control);
behavior = new TableCellBehavior(control);
....
}
The requirement is replace the mousePressed behavior (in jdk9 context). The idea is to grab super's field reflectively, dispose all its mappings and install the custom behavior. For some reason that I don't understand, the old bindings are still active (though the old mappings are empty!) and are invoked before the new bindings.
Below is a runnable example to play with: the mapping to mousePressed is simply implemented to do nothing, particularly to not invoke super. To see the old bindings at work, I set a conditional debug breakpoint at CellBehaviorBase.mousePressed like (in Eclipse):
System.out.println("mousePressed super");
new RuntimeException("whoIsCalling: " + getNode().getClass()).printStackTrace();
return false;
Run a debug and click into any cell, then the output is:
mousePressed super
java.lang.RuntimeException: whoIsCalling: class de.swingempire.fx.scene.control.cell.TableCellBehaviorReplace$PlainCustomTableCell
at com.sun.javafx.scene.control.behavior.CellBehaviorBase.mousePressed(CellBehaviorBase.java:169)
at com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
//... lots more of event dispatching
// until finally the output in my custom cell behavior
Feb. 02, 2016 3:14:02 NACHM. de.swingempire.fx.scene.control.cell.TableCellBehaviorReplace$PlainCustomTableCellBehavior mousePressed
INFORMATION: short-circuit super: Bulgarisch
I would expect to only see the very last part, that is the printout by my custom behavior. It feels like I'm somehow fundamentally off - but can't nail it. Ideas?
The runnable code (sorry for its length, most is boiler-plate, though):
public class TableCellBehaviorReplace extends Application {
private final ObservableList<Locale> locales =
FXCollections.observableArrayList(Locale.getAvailableLocales());
private Parent getContent() {
TableView<Locale> table = createLocaleTable();
BorderPane content = new BorderPane(table);
return content;
}
private TableView<Locale> createLocaleTable() {
TableView<Locale> table = new TableView<>(locales);
TableColumn<Locale, String> name = new TableColumn<>("Name");
name.setCellValueFactory(new PropertyValueFactory<>("displayName"));
name.setCellFactory(p -> new PlainCustomTableCell<>());
TableColumn<Locale, String> lang = new TableColumn<>("Language");
lang.setCellValueFactory(new PropertyValueFactory<>("displayLanguage"));
lang.setCellFactory(p -> new PlainCustomTableCell<>());
table.getColumns().addAll(name, lang);
return table;
}
/**
* Custom skin that installs custom Behavior. Note: this is dirty!
* Access super's behavior, dispose to get rid off its handlers, install
* custom behavior.
*/
public static class PlainCustomTableCellSkin<S, T> extends TableCellSkin<S, T> {
private BehaviorBase<?> replacedBehavior;
public PlainCustomTableCellSkin(TableCell<S, T> control) {
super(control);
replaceBehavior();
}
private void replaceBehavior() {
BehaviorBase<?> old = (BehaviorBase<?>) invokeGetField(TableCellSkin.class, this, "behavior");
old.dispose();
// at this point, InputMap mappings are empty:
// System.out.println("old mappings: " + old.getInputMap().getMappings().size());
replacedBehavior = new PlainCustomTableCellBehavior<>(getSkinnable());
}
#Override
public void dispose() {
replacedBehavior.dispose();
super.dispose();
}
}
/**
* Custom behavior that's meant to override basic handlers. Here: short-circuit
* mousePressed.
*/
public static class PlainCustomTableCellBehavior<S, T> extends TableCellBehavior<S, T> {
public PlainCustomTableCellBehavior(TableCell<S, T> control) {
super(control);
}
#Override
public void mousePressed(MouseEvent e) {
if (true) {
LOG.info("short-circuit super: " + getNode().getItem());
return;
}
super.mousePressed(e);
}
}
/**
* C&P of default tableCell in TableColumn. Extended to install custom
* skin.
*/
public static class PlainCustomTableCell<S, T> extends TableCell<S, T> {
public PlainCustomTableCell() {
}
#Override protected void updateItem(T item, boolean empty) {
if (item == getItem()) return;
super.updateItem(item, empty);
if (item == null) {
super.setText(null);
super.setGraphic(null);
} else if (item instanceof Node) {
super.setText(null);
super.setGraphic((Node)item);
} else {
super.setText(item.toString());
super.setGraphic(null);
}
}
#Override
protected Skin<?> createDefaultSkin() {
return new PlainCustomTableCellSkin<>(this);
}
}
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setScene(new Scene(getContent(), 400, 200));
primaryStage.setTitle(FXUtils.version());
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
/**
* Reflectively access super field.
*/
public static Object invokeGetField(Class source, Object target, String name) {
try {
Field field = source.getDeclaredField(name);
field.setAccessible(true);
return field.get(target);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
#SuppressWarnings("unused")
private static final Logger LOG = Logger
.getLogger(TableCellBehaviorReplace.class.getName());
}
Edit
The suggestion inherit from the abstract skin XXSkinBase instead of the concrete XXSkin (then you are free to install whatever behavior you want, dude :-) is very reasonable and should be the first option. In the particular case of XX being TableCell, that's currently not possible, as the base class contains abstract package-private methods. Also, there are XX that don't have an abstract base (like f.i. ListCell).
Might be a bug in InputMap:
Digging into the sources I found some internal book-keeping (eventTypeMappings) parallel to mappings (these are the handlers). InputMap is listening to changes in mappings and updates the internal book-keeping on changes
mappings.addListener((ListChangeListener<Mapping<?>>) c -> {
while (c.next()) {
// TODO handle mapping removal
if (c.wasRemoved()) {
for (Mapping<?> mapping : c.getRemoved()) {
removeMapping(mapping);
}
}
// removeMapping
private void removeMapping(Mapping<?> mapping) {
// TODO
}
Meaning that the internal structure is never cleaned, particularly not when the mappings are removed in behavior.dispose(). When looking up eventHandlers - by inputMap.handle(e), see debug stacktrace shown in the question - the old handler is found in the internal book-keeping structure.
Joys of early experiments ... ;-)
At the end, a (very dirty, very hacky!) solution is to take over InputMap's job and force a cleanup of the internals:
private void replaceBehavior() {
BehaviorBase<?> old = (BehaviorBase<?>) invokeGetField(TableCellSkin.class, this, "behavior");
old.dispose();
cleanupInputMap(old.getInputMap());
// at this point, InputMap mappings are empty:
// System.out.println("old mappings: " + old.getInputMap().getMappings().size());
replacedBehavior = new PlainCustomTableCellBehavior<>(getSkinnable());
}
/**
* This is a hack around InputMap not cleaning up internals on removing mappings.
* We remove MousePressed/MouseReleased/MouseDragged mappings from the internal map.
* Beware: obviously this is dirty!
*
* #param inputMap
*/
private void cleanupInputMap(InputMap<?> inputMap) {
Map eventTypeMappings = (Map) invokeGetField(InputMap.class, inputMap, "eventTypeMappings");
eventTypeMappings.remove(MouseEvent.MOUSE_PRESSED);
eventTypeMappings.remove(MouseEvent.MOUSE_RELEASED);
eventTypeMappings.remove(MouseEvent.MOUSE_DRAGGED);
}
BTW: just in case anybody is wondering wtf - without, my hack around the missing commitOnFocusLost when editing a cell stopped working in java-9.
Try in PlainCustomTableCellSkin to inherit from the abstract class TableCellSkinBase rather than from TableCellSkin.
Then you can call the super constructor, which takes an TableCellBehaviorBase object as additional param.
Then you can save your time replacing it, by initializing it directly with the right one.
Just for more claryfication:
TableCellSkin extends TableCellSkinBase
TableCellBehavior extends TableCellBehaviorBase
One more thing. You need to also call super.init(tableCell) in your constructor.
Take the TableCellSkin class as reference.

How can I register a (boundless) type hierarchy using Autofac?

I've got a Factory interface (along with concrete implementations):
// foo.dll
interface IFooProvider
{
T GetFoo<T>()
where T : BaseFoo;
}
My BaseFoo is not abstract, but only its subclasses are actually useful:
// shared.dll
class BaseFoo
{ ... }
I've also got a (potentially unbounded) number of subclasses of BaseFoo across many assemblies:
// foo.dll
class AFoo : BaseFoo
{ ... }
// foo2.dll
class BFoo : BaseFoo
{ ... }
... and many more ...
Naively, I had been registering the Foo-derived classes in an unsurprising way:
// foo.dll
class ConcreteFooRegistration : Module
{
protected override void Load(ContainerBuilder builder)
{
// a concrete FooProvider is registered elsewhere
builder.Register(c => c.Resolve<IFooProvider>().GetFoo<AFoo>());
builder.Register(c => c.Resolve<IFooProvider>().GetFoo<BFoo>());
...
}
}
But this implies that:
the assembly containing ConcreteFooRegistration (e.g. foo.dll) also contains some/all of AFoo, BFoo, etc.
the assembly containing ConcreteFooRegistration (e.g. foo.dll) references the assemblies (e.g. foo2.dll) containing some/all of AFoo, BFoo, etc.
IFooProvider be available to any other assembly containing BaseFoo-derived classes and the Module that registers them
For sake of discussion, assume that none of these is possible and/or desirable. That is, I'm looking for solutions other than "move IFooProvider into shared.dll".
Since AFoo and BFoo are the real dependencies that other types are interested in, and IFooProvider is (from that perspective) just an instantiation detail, I got inspired by the Autofac+Serilog integration that Nicholas came up with. I've used a similar approach elsewhere, so I wrote up an AttachToComponentRegistration() implementation:
// foo.dll
class ConcreteFooRegistration : Module
{
// NOTICE: there's no Load() method
protected override void AttachToComponentRegistration(...)
{
...
registration.Preparing += (sender, e) =>
{
var pFoo = new ResolvedParameter(
(p, i) => p.ParameterType.IsAssignableTo<BaseFoo>(),
(p, i) => i.Resolve<IFooProvider>().GetFoo<FooWeNeed>()
);
e.Parameters = new [] { pFoo }.Concat(e.Parameters);
};
}
}
This was successful, in that I was able to remove all the individual BaseFoo-derived registrations from ConcreteFooRegistration and still successfully resolve arbitrary BaseFoo-derived dependencies with constructor injection:
// other.dll:
class WorkerRegisteration : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<Worker>();
// NOTICE: FooYouDidntKnowAbout is NOT explicitly registered
}
}
class Worker
{
public Worker(FooYouDidntKnowAbout foo)
{ ... }
...
}
BUT: now I can't arbitrarily resolve AFoo outside of constructor injection:
builder.Register(c =>
{
// here's one use for a BaseFoo outside constructor injection
var foo = c.Resolve<AFoo>();
if (foo.PropValue1)
return new OtherClass(foo.PropValue2);
else
return new YetAnother(foo.PropValue3);
}
...
builder.Register(c =>
{
// here's another
var foo = c.Resolve<AFoo>();
return c.Resolve(foo.TypePropValue);
});
Assuming that publishing IFooProvider as a public export of foo.dll or moving it to shared.dll is undesirable/impossible, thus eliminating the naive-but-unsurprising implementation above, (how) can I set up my registrations to be able to resolve arbitrary subclasses of BaseFoo from anywhere?
Thanks!
I think what you're looking for is a registration source. A registration source is a dynamic "registration provider" you can use to feed Autofac registrations as needed.
As of this writing, the doc on registration sources is pretty thin (I just haven't gotten a chance to write it) but there's a blog article with some details about it.
Registration sources are how Autofac supports things like IEnumerable<T> or Lazy<T> - we don't require you actually register every collection, instead we dynamically feed the registrations into the container using sources.
Anyway, let me write you up a sample here and maybe I can use it later to massage it into the docs, eh? :)
First, let's define a very simple factory and implementation. I'm going to use "Service" instead of "Foo" here because my brain stumbles after it sees "foo" too many times. That's a "me" thing. But I digress.
public interface IServiceProvider
{
T GetService<T>() where T : BaseService;
}
public class ServiceProvider : IServiceProvider
{
public T GetService<T>() where T : BaseService
{
return (T)Activator.CreateInstance(typeof(T));
}
}
OK, now let's make the service types. Obviously for this sample all the types are sort of in one assembly, but when your code references the type and the JIT brings it in from some other assembly, it'll work just the same. Don't worry about cross-assembly stuff for this.
public abstract class BaseService { }
public class ServiceA : BaseService { }
public class ServiceB : BaseService { }
Finally, a couple of classes that consume the services, just so we can see it working.
public class ConsumerA
{
public ConsumerA(ServiceA service)
{
Console.WriteLine("ConsumerA: {0}", service.GetType());
}
}
public class ConsumerB
{
public ConsumerB(ServiceB service)
{
Console.WriteLine("ConsumerB: {0}", service.GetType());
}
}
Good.
Here's the important bit, now: the registration source. The registration source is where you will:
Determine if the resolve operation is asking for a BaseService type or not. If it's not, then you can't handle it so you'll bail.
Build up the dynamic registration for the specific type of BaseService derivative being requested, which will include the lambda that invokes the provider/factory to get the instance.
Return the dynamic registration to the resolve operation so it can do the work.
It looks like this:
using Autofac;
using Autofac.Core;
using Autofac.Core.Activators.Delegate;
using Autofac.Core.Lifetime;
using Autofac.Core.Registration;
public class ServiceRegistrationSource : IRegistrationSource
{
public IEnumerable<IComponentRegistration> RegistrationsFor(
Service service,
Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
var swt = service as IServiceWithType;
if(swt == null || !typeof(BaseService).IsAssignableFrom(swt.ServiceType))
{
// It's not a request for the base service type, so skip it.
return Enumerable.Empty<IComponentRegistration>();
}
// This is where the magic happens!
var registration = new ComponentRegistration(
Guid.NewGuid(),
new DelegateActivator(swt.ServiceType, (c, p) =>
{
// The factory method is generic, but we're working
// at a reflection level, so there's a bit of crazy
// to deal with.
var provider = c.Resolve<IServiceProvider>();
var method = provider.GetType().GetMethod("GetService").MakeGenericMethod(swt.ServiceType);
return method.Invoke(provider, null);
}),
new CurrentScopeLifetime(),
InstanceSharing.None,
InstanceOwnership.OwnedByLifetimeScope,
new [] { service },
new Dictionary<string, object>());
return new IComponentRegistration[] { registration };
}
public bool IsAdapterForIndividualComponents { get{ return false; } }
}
It looks complex, but it's not too bad.
The last step is to get the factory registered as well as the registration source. For my sample, I put those in an Autofac module so they're both registered together - it doesn't make sense to have one without the other.
public class ServiceProviderModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<ServiceProvider>().As<IServiceProvider>();
builder.RegisterSource(new ServiceRegistrationSource());
}
}
Finally, let's see it in action. If I throw this code into a console app...
static void Main()
{
var builder = new ContainerBuilder();
builder.RegisterType<ConsumerA>();
builder.RegisterType<ConsumerB>();
builder.RegisterModule<ServiceProviderModule>();
var container = builder.Build();
using(var scope = container.BeginLifetimeScope())
{
var a = scope.Resolve<ConsumerA>();
var b = scope.Resolve<ConsumerB>();
}
}
What you end up with on the console is:
ConsumerA: ServiceA
ConsumerB: ServiceB
Note I had to register my consuming classes but I didn't explicitly register any of the BaseService-derived classes - that was all done by the registration source.
If you want to see more registration source samples, check out the Autofac source, particularly under the Autofac.Features namespace. There you'll find things like the CollectionRegistrationSource, which is responsible for handling IEnumerable<T> support.

Log additional info OnEntry or OnSuccess

is there a way to log username or user id (or some additional data) together with parameters on OnEntry/OnSuccess/OnException.
I need my log record to look like:
"... Method MethodName invoked with params [param1: value1, param2: value2 ...] by User : [username]"
Thanks.
The following code is taken from the Postsharp documentation site at Trace Sample with some minor modification
using System;
using System.Diagnostics;
using System.Reflection;
using PostSharp.Aspects;
namespace Samples
{
[Serializable]
public sealed class TraceAttribute : OnMethodBoundaryAspect
{
// This field is initialized and serialized at build time, then deserialized at runtime.
private readonly string category;
// These fields are initialized at runtime. They do not need to be serialized.
[NonSerialized] private string enteringMessage;
[NonSerialized] private string exitingMessage;
// Default constructor, invoked at build time.
public TraceAttribute()
{
}
// Constructor specifying the tracing category, invoked at build time.
public TraceAttribute(string category)
{
this.category = category;
}
// Invoked only once at runtime from the static constructor of type declaring the target method.
public override void RuntimeInitialize(MethodBase method)
{
string methodName = method.DeclaringType.FullName + method.Name;
this.enteringMessage = "Entering " + methodName;
this.exitingMessage = "Exiting " + methodName;
}
// Invoked at runtime before that target method is invoked.
public override void OnEntry(MethodExecutionArgs args)
{
Trace.WriteLine(this.enteringMessage, this.category);
DisplayArgs(args);
}
// Invoked at runtime after the target method is invoked (in a finally block).
public override void OnExit(MethodExecutionArgs args)
{
Trace.WriteLine(this.exitingMessage, this.category);
DisplayArgs(args);
}
}
}
private void DisplayArgs(MethodExecutionArgs args)
{
var parameters = args.Method.GetParameters();
var arguments = args.Arguments;
var zipped = parameters.Zip(arguments, (f,s) => f.Name + ":" + s == null ? "null" : s.ToString());
string traceLine = string.Format("invoked with params [{0}] by User:[{1}]", string.Join(",", zipped),
System.Security.Principal.WindowsIdentity.GetCurrent().Name);
System.Diagnostics.Trace.TraceInformation(traceLine);
}

Using GWT Editors with a complex usecase

I'm trying to create a page which is very similar to the Google Form creation page.
This is how I am attempting to model it using the GWT MVP framework (Places and Activities), and Editors.
CreateFormActivity (Activity and presenter)
CreateFormView (interface for view, with nested Presenter interface)
CreateFormViewImpl (implements CreateFormView and Editor< FormProxy >
CreateFormViewImpl has the following sub-editors:
TextBox title
TextBox description
QuestionListEditor questionList
QuestionListEditor implements IsEditor< ListEditor< QuestionProxy, QuestionEditor>>
QuestionEditor implements Editor < QuestionProxy>
QuestionEditor has the following sub-editors:
TextBox questionTitle
TextBox helpText
ValueListBox questionType
An optional subeditor for each question type below.
An editor for each question type:
TextQuestionEditor
ParagraphTextQuestionEditor
MultipleChoiceQuestionEditor
CheckboxesQuestionEditor
ListQuestionEditor
ScaleQuestionEditor
GridQuestionEditor
Specific Questions:
What is the correct way to add / remove questions from the form. (see follow up question)
How should I go about creating the Editor for each question type? I attempted to listen to the questionType value changes, I'm not sure what to do after. (answered by BobV)
Should each question-type-specific editor be wrapper with an optionalFieldEditor? Since only one of can be used at a time. (answered by BobV)
How to best manage creating/removing objects deep in the object hierarchy. Ex) Specifying answers for a question number 3 which is of type multiple choice question. (see follow up question)
Can OptionalFieldEditor editor be used to wrap a ListEditor? (answered by BobV)
Implementation based on Answer
The Question Editor
public class QuestionDataEditor extends Composite implements
CompositeEditor<QuestionDataProxy, QuestionDataProxy, Editor<QuestionDataProxy>>,
LeafValueEditor<QuestionDataProxy>, HasRequestContext<QuestionDataProxy> {
interface Binder extends UiBinder<Widget, QuestionDataEditor> {}
private CompositeEditor.EditorChain<QuestionDataProxy, Editor<QuestionDataProxy>> chain;
private QuestionBaseDataEditor subEditor = null;
private QuestionDataProxy currentValue = null;
#UiField
SimplePanel container;
#UiField(provided = true)
#Path("dataType")
ValueListBox<QuestionType> dataType = new ValueListBox<QuestionType>(new Renderer<QuestionType>() {
#Override
public String render(final QuestionType object) {
return object == null ? "" : object.toString();
}
#Override
public void render(final QuestionType object, final Appendable appendable) throws IOException {
if (object != null) {
appendable.append(object.toString());
}
}
});
private RequestContext ctx;
public QuestionDataEditor() {
initWidget(GWT.<Binder> create(Binder.class).createAndBindUi(this));
dataType.setValue(QuestionType.BooleanQuestionType, true);
dataType.setAcceptableValues(Arrays.asList(QuestionType.values()));
/*
* The type drop-down UI element is an implementation detail of the
* CompositeEditor. When a question type is selected, the editor will
* call EditorChain.attach() with an instance of a QuestionData subtype
* and the type-specific sub-Editor.
*/
dataType.addValueChangeHandler(new ValueChangeHandler<QuestionType>() {
#Override
public void onValueChange(final ValueChangeEvent<QuestionType> event) {
QuestionDataProxy value;
switch (event.getValue()) {
case MultiChoiceQuestionData:
value = ctx.create(QuestionMultiChoiceDataProxy.class);
setValue(value);
break;
case BooleanQuestionData:
default:
final QuestionNumberDataProxy value2 = ctx.create(BooleanQuestionDataProxy.class);
value2.setPrompt("this value doesn't show up");
setValue(value2);
break;
}
}
});
}
/*
* The only thing that calls createEditorForTraversal() is the PathCollector
* which is used by RequestFactoryEditorDriver.getPaths().
*
* My recommendation is to always return a trivial instance of your question
* type editor and know that you may have to amend the value returned by
* getPaths()
*/
#Override
public Editor<QuestionDataProxy> createEditorForTraversal() {
return new QuestionNumberDataEditor();
}
#Override
public void flush() {
//XXX this doesn't work, no data is returned
currentValue = chain.getValue(subEditor);
}
/**
* Returns an empty string because there is only ever one sub-editor used.
*/
#Override
public String getPathElement(final Editor<QuestionDataProxy> subEditor) {
return "";
}
#Override
public QuestionDataProxy getValue() {
return currentValue;
}
#Override
public void onPropertyChange(final String... paths) {
}
#Override
public void setDelegate(final EditorDelegate<QuestionDataProxy> delegate) {
}
#Override
public void setEditorChain(final EditorChain<QuestionDataProxy, Editor<QuestionDataProxy>> chain) {
this.chain = chain;
}
#Override
public void setRequestContext(final RequestContext ctx) {
this.ctx = ctx;
}
/*
* The implementation of CompositeEditor.setValue() just creates the
* type-specific sub-Editor and calls EditorChain.attach().
*/
#Override
public void setValue(final QuestionDataProxy value) {
// if (currentValue != null && value == null) {
chain.detach(subEditor);
// }
QuestionType type = null;
if (value instanceof QuestionMultiChoiceDataProxy) {
if (((QuestionMultiChoiceDataProxy) value).getCustomList() == null) {
((QuestionMultiChoiceDataProxy) value).setCustomList(new ArrayList<CustomListItemProxy>());
}
type = QuestionType.CustomList;
subEditor = new QuestionMultipleChoiceDataEditor();
} else {
type = QuestionType.BooleanQuestionType;
subEditor = new BooleanQuestionDataEditor();
}
subEditor.setRequestContext(ctx);
currentValue = value;
container.clear();
if (value != null) {
dataType.setValue(type, false);
container.add(subEditor);
chain.attach(value, subEditor);
}
}
}
Question Base Data Editor
public interface QuestionBaseDataEditor extends HasRequestContext<QuestionDataProxy>, IsWidget {
}
Example Subtype
public class BooleanQuestionDataEditor extends Composite implements QuestionBaseDataEditor {
interface Binder extends UiBinder<Widget, BooleanQuestionDataEditor> {}
#Path("prompt")
#UiField
TextBox prompt = new TextBox();
public QuestionNumberDataEditor() {
initWidget(GWT.<Binder> create(Binder.class).createAndBindUi(this));
}
#Override
public void setRequestContext(final RequestContext ctx) {
}
}
The only issue left is that QuestionData subtype specific data isn't being displayed, or flushed. I think it has to do with the Editor setup I'm using.
For example, The value for prompt in the BooleanQuestionDataEditor is neither set nor flushed, and is null in the rpc payload.
My guess is: Since the QuestionDataEditor implements LeafValueEditor, the driver will not visit the subeditor, even though it has been attached.
Big thanks to anyone who can help!!!
Fundamentally, you want a CompositeEditor to handle cases where objects are dynamically added or removed from the Editor hierarchy. The ListEditor and OptionalFieldEditor adaptors implement CompositeEditor.
If the information required for the different types of questions is fundamentally orthogonal, then multiple OptionalFieldEditor could be used with different fields, one for each question type. This will work when you have only a few question types, but won't really scale well in the future.
A different approach, that will scale better would be to use a custom implementation of a CompositeEditor + LeafValueEditor that handles a polymorphic QuestionData type hierarchy. The type drop-down UI element would become an implementation detail of the CompositeEditor. When a question type is selected, the editor will call EditorChain.attach() with an instance of a QuestionData subtype and the type-specific sub-Editor. The newly-created QuestionData instance should be retained to implement LeafValueEditor.getValue(). The implementation of CompositeEditor.setValue() just creates the type-specific sub-Editor and calls EditorChain.attach().
FWIW, OptionalFieldEditor can be used with ListEditor or any other editor type.
We implemented similar approach (see accepted answer) and it works for us like this.
Since driver is initially unaware of simple editor paths that might be used by sub-editors, every sub-editor has own driver:
public interface CreatesEditorDriver<T> {
RequestFactoryEditorDriver<T, ? extends Editor<T>> createDriver();
}
public interface RequestFactoryEditor<T> extends CreatesEditorDriver<T>, Editor<T> {
}
Then we use the following editor adapter that would allow any sub-editor that implements RequestFactoryEditor to be used. This is our workaround to support polimorphism in editors:
public static class DynamicEditor<T>
implements LeafValueEditor<T>, CompositeEditor<T, T, RequestFactoryEditor<T>>, HasRequestContext<T> {
private RequestFactoryEditorDriver<T, ? extends Editor<T>> subdriver;
private RequestFactoryEditor<T> subeditor;
private T value;
private EditorDelegate<T> delegate;
private RequestContext ctx;
public static <T> DynamicEditor<T> of(RequestFactoryEditor<T> subeditor) {
return new DynamicEditor<T>(subeditor);
}
protected DynamicEditor(RequestFactoryEditor<T> subeditor) {
this.subeditor = subeditor;
}
#Override
public void setValue(T value) {
this.value = value;
subdriver = null;
if (null != value) {
RequestFactoryEditorDriver<T, ? extends Editor<T>> newSubdriver = subeditor.createDriver();
if (null != ctx) {
newSubdriver.edit(value, ctx);
} else {
newSubdriver.display(value);
}
subdriver = newSubdriver;
}
}
#Override
public T getValue() {
return value;
}
#Override
public void flush() {
if (null != subdriver) {
subdriver.flush();
}
}
#Override
public void onPropertyChange(String... paths) {
}
#Override
public void setDelegate(EditorDelegate<T> delegate) {
this.delegate = delegate;
}
#Override
public RequestFactoryEditor<T> createEditorForTraversal() {
return subeditor;
}
#Override
public String getPathElement(RequestFactoryEditor<T> subEditor) {
return delegate.getPath();
}
#Override
public void setEditorChain(EditorChain<T, RequestFactoryEditor<T>> chain) {
}
#Override
public void setRequestContext(RequestContext ctx) {
this.ctx = ctx;
}
}
Our example sub-editor:
public static class VirtualProductEditor implements RequestFactoryEditor<ProductProxy> {
interface Driver extends RequestFactoryEditorDriver<ProductProxy, VirtualProductEditor> {}
private static final Driver driver = GWT.create(Driver.class);
public Driver createDriver() {
driver.initialize(this);
return driver;
}
...
}
Our usage example:
#Path("")
DynamicEditor<ProductProxy> productDetailsEditor;
...
public void setProductType(ProductType type){
if (ProductType.VIRTUAL==type){
productDetailsEditor = DynamicEditor.of(new VirtualProductEditor());
} else if (ProductType.PHYSICAL==type){
productDetailsEditor = DynamicEditor.of(new PhysicalProductEditor());
}
}
Would be great to hear your comments.
Regarding your question why subtype specific data isn't displayed or flushed:
My scenario is a little bit different but I made the following observation:
GWT editor databinding does not work as one would expect with abstract editors in the editor hierarchy. The subEditor declared in your QuestionDataEditor is of type QuestionBaseDataEditor and this is fully abstract type (an interface). When looking for fields/sub editors to populate with data/flush GWT takes all the fields declared in this type. Since QuestionBaseDataEditor has no sub editors declared nothing is displayed/flushed. From debugging I found out that is happens due to GWT using a generated EditorDelegate for that abstract type rather than the EditorDelegate for the concrete subtype present at that moment.
In my case all the concrete sub editors had the same types of leaf value editors (I had two different concrete editors one to display and one to edit the same bean type) so I could do something like this to work around this limitation:
interface MyAbstractEditor1 extends Editor<MyBean>
{
LeafValueEditor<String> description();
}
// or as an alternative
abstract class MyAbstractEditor2 implements Editor<MyBean>
{
#UiField protected LeafValueEditor<String> name;
}
class MyConcreteEditor extends MyAbstractEditor2 implements MyAbstractEditor1
{
#UiField TextBox description;
public LeafValueEditor<String> description()
{
return description;
}
// super.name is bound to a TextBox using UiBinder :)
}
Now GWT finds the subeditors in the abstract base class and in both cases I get the corresponding fields name and description populated and flushed.
Unfortunately this approach is not suitable when the concrete subeditors have different values in your bean structure to edit :(
I think this is a bug of the editors framework GWT code generation, that can only be solved by the GWT development team.
Isn't the fundamental problem that the binding happens at compile time so will only bind to QuestionDataProxy so won't have sub-type specific bindings? The CompositeEditor javadoc says "An interface that indicates that a given Editor is composed of an unknown number of sub-Editors all of the same type" so that rules this usage out?
At my current job I'm pushing to avoid polymorphism altogether as the RDBMS doesn't support it either. Sadly we do have some at the moment so I'm experimenting with a dummy wrapper class that exposes all the sub-types with specific getters so the compiler has something to work on. Not pretty though.
Have you seen this post: http://markmail.org/message/u2cff3mfbiboeejr this seems along the right lines.
I'm a bit worried about code bloat though.
Hope that makes some sort of sense!

Stop DataContractSerializer putting in namespace? [duplicate]

The code looks like this:
StringBuilder builder = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
using (XmlWriter xmlWriter = XmlWriter.Create(builder, settings))
{
XmlSerializer s = new XmlSerializer(objectToSerialize.GetType());
s.Serialize(xmlWriter, objectToSerialize);
}
The resulting serialized document includes namespaces, like so:
<message xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"
xmlns="urn:something">
...
</message>
To remove the xsi and xsd namespaces, I can follow the answer from How to serialize an object to XML without getting xmlns=”…”?.
I want my message tag as <message> (without any namespace attributes). How can I do this?
...
XmlSerializer s = new XmlSerializer(objectToSerialize.GetType());
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("","");
s.Serialize(xmlWriter, objectToSerialize, ns);
This is the 2nd of two answers.
If you want to just strip all namespaces arbitrarily from a document during serialization, you can do this by implementing your own XmlWriter.
The easiest way is to derive from XmlTextWriter and override the StartElement method that emits namespaces. The StartElement method is invoked by the XmlSerializer when emitting any elements, including the root. By overriding the namespace for each element, and replacing it with the empty string, you've stripped the namespaces from the output.
public class NoNamespaceXmlWriter : XmlTextWriter
{
//Provide as many contructors as you need
public NoNamespaceXmlWriter(System.IO.TextWriter output)
: base(output) { Formatting= System.Xml.Formatting.Indented;}
public override void WriteStartDocument () { }
public override void WriteStartElement(string prefix, string localName, string ns)
{
base.WriteStartElement("", localName, "");
}
}
Suppose this is the type:
// explicitly specify a namespace for this type,
// to be used during XML serialization.
[XmlRoot(Namespace="urn:Abracadabra")]
public class MyTypeWithNamespaces
{
// private fields backing the properties
private int _Epoch;
private string _Label;
// explicitly define a distinct namespace for this element
[XmlElement(Namespace="urn:Whoohoo")]
public string Label
{
set { _Label= value; }
get { return _Label; }
}
// this property will be implicitly serialized to XML using the
// member name for the element name, and inheriting the namespace from
// the type.
public int Epoch
{
set { _Epoch= value; }
get { return _Epoch; }
}
}
Here's how you would use such a thing during serialization:
var o2= new MyTypeWithNamespaces { ..intializers.. };
var builder = new System.Text.StringBuilder();
using ( XmlWriter writer = new NoNamespaceXmlWriter(new System.IO.StringWriter(builder)))
{
s2.Serialize(writer, o2, ns2);
}
Console.WriteLine("{0}",builder.ToString());
The XmlTextWriter is sort of broken, though. According to the reference doc, when it writes it does not check for the following:
Invalid characters in attribute and element names.
Unicode characters that do not fit the specified encoding. If the Unicode
characters do not fit the specified
encoding, the XmlTextWriter does not
escape the Unicode characters into
character entities.
Duplicate attributes.
Characters in the DOCTYPE public
identifier or system identifier.
These problems with XmlTextWriter have been around since v1.1 of the .NET Framework, and they will remain, for backward compatibility. If you have no concerns about those problems, then by all means use the XmlTextWriter. But most people would like a bit more reliability.
To get that, while still suppressing namespaces during serialization, instead of deriving from XmlTextWriter, define a concrete implementation of the abstract XmlWriter and its 24 methods.
An example is here:
public class XmlWriterWrapper : XmlWriter
{
protected XmlWriter writer;
public XmlWriterWrapper(XmlWriter baseWriter)
{
this.Writer = baseWriter;
}
public override void Close()
{
this.writer.Close();
}
protected override void Dispose(bool disposing)
{
((IDisposable) this.writer).Dispose();
}
public override void Flush()
{
this.writer.Flush();
}
public override string LookupPrefix(string ns)
{
return this.writer.LookupPrefix(ns);
}
public override void WriteBase64(byte[] buffer, int index, int count)
{
this.writer.WriteBase64(buffer, index, count);
}
public override void WriteCData(string text)
{
this.writer.WriteCData(text);
}
public override void WriteCharEntity(char ch)
{
this.writer.WriteCharEntity(ch);
}
public override void WriteChars(char[] buffer, int index, int count)
{
this.writer.WriteChars(buffer, index, count);
}
public override void WriteComment(string text)
{
this.writer.WriteComment(text);
}
public override void WriteDocType(string name, string pubid, string sysid, string subset)
{
this.writer.WriteDocType(name, pubid, sysid, subset);
}
public override void WriteEndAttribute()
{
this.writer.WriteEndAttribute();
}
public override void WriteEndDocument()
{
this.writer.WriteEndDocument();
}
public override void WriteEndElement()
{
this.writer.WriteEndElement();
}
public override void WriteEntityRef(string name)
{
this.writer.WriteEntityRef(name);
}
public override void WriteFullEndElement()
{
this.writer.WriteFullEndElement();
}
public override void WriteProcessingInstruction(string name, string text)
{
this.writer.WriteProcessingInstruction(name, text);
}
public override void WriteRaw(string data)
{
this.writer.WriteRaw(data);
}
public override void WriteRaw(char[] buffer, int index, int count)
{
this.writer.WriteRaw(buffer, index, count);
}
public override void WriteStartAttribute(string prefix, string localName, string ns)
{
this.writer.WriteStartAttribute(prefix, localName, ns);
}
public override void WriteStartDocument()
{
this.writer.WriteStartDocument();
}
public override void WriteStartDocument(bool standalone)
{
this.writer.WriteStartDocument(standalone);
}
public override void WriteStartElement(string prefix, string localName, string ns)
{
this.writer.WriteStartElement(prefix, localName, ns);
}
public override void WriteString(string text)
{
this.writer.WriteString(text);
}
public override void WriteSurrogateCharEntity(char lowChar, char highChar)
{
this.writer.WriteSurrogateCharEntity(lowChar, highChar);
}
public override void WriteValue(bool value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(DateTime value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(decimal value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(double value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(int value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(long value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(object value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(float value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(string value)
{
this.writer.WriteValue(value);
}
public override void WriteWhitespace(string ws)
{
this.writer.WriteWhitespace(ws);
}
public override XmlWriterSettings Settings
{
get
{
return this.writer.Settings;
}
}
protected XmlWriter Writer
{
get
{
return this.writer;
}
set
{
this.writer = value;
}
}
public override System.Xml.WriteState WriteState
{
get
{
return this.writer.WriteState;
}
}
public override string XmlLang
{
get
{
return this.writer.XmlLang;
}
}
public override System.Xml.XmlSpace XmlSpace
{
get
{
return this.writer.XmlSpace;
}
}
}
Then, provide a derived class that overrides the StartElement method, as before:
public class NamespaceSupressingXmlWriter : XmlWriterWrapper
{
//Provide as many contructors as you need
public NamespaceSupressingXmlWriter(System.IO.TextWriter output)
: base(XmlWriter.Create(output)) { }
public NamespaceSupressingXmlWriter(XmlWriter output)
: base(XmlWriter.Create(output)) { }
public override void WriteStartElement(string prefix, string localName, string ns)
{
base.WriteStartElement("", localName, "");
}
}
And then use this writer like so:
var o2= new MyTypeWithNamespaces { ..intializers.. };
var builder = new System.Text.StringBuilder();
var settings = new XmlWriterSettings { OmitXmlDeclaration = true, Indent= true };
using ( XmlWriter innerWriter = XmlWriter.Create(builder, settings))
using ( XmlWriter writer = new NamespaceSupressingXmlWriter(innerWriter))
{
s2.Serialize(writer, o2, ns2);
}
Console.WriteLine("{0}",builder.ToString());
Credit for this to Oleg Tkachenko.
After reading Microsoft's documentation and several solutions online, I have discovered the solution to this problem. It works with both the built-in XmlSerializer and custom XML serialization via IXmlSerialiazble.
To wit, I'll use the same MyTypeWithNamespaces XML sample that's been used in the answers to this question so far.
[XmlRoot("MyTypeWithNamespaces", Namespace="urn:Abracadabra", IsNullable=false)]
public class MyTypeWithNamespaces
{
// As noted below, per Microsoft's documentation, if the class exposes a public
// member of type XmlSerializerNamespaces decorated with the
// XmlNamespacesDeclarationAttribute, then the XmlSerializer will utilize those
// namespaces during serialization.
public MyTypeWithNamespaces( )
{
this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
// Don't do this!! Microsoft's documentation explicitly says it's not supported.
// It doesn't throw any exceptions, but in my testing, it didn't always work.
// new XmlQualifiedName(string.Empty, string.Empty), // And don't do this:
// new XmlQualifiedName("", "")
// DO THIS:
new XmlQualifiedName(string.Empty, "urn:Abracadabra") // Default Namespace
// Add any other namespaces, with prefixes, here.
});
}
// If you have other constructors, make sure to call the default constructor.
public MyTypeWithNamespaces(string label, int epoch) : this( )
{
this._label = label;
this._epoch = epoch;
}
// An element with a declared namespace different than the namespace
// of the enclosing type.
[XmlElement(Namespace="urn:Whoohoo")]
public string Label
{
get { return this._label; }
set { this._label = value; }
}
private string _label;
// An element whose tag will be the same name as the property name.
// Also, this element will inherit the namespace of the enclosing type.
public int Epoch
{
get { return this._epoch; }
set { this._epoch = value; }
}
private int _epoch;
// Per Microsoft's documentation, you can add some public member that
// returns a XmlSerializerNamespaces object. They use a public field,
// but that's sloppy. So I'll use a private backed-field with a public
// getter property. Also, per the documentation, for this to work with
// the XmlSerializer, decorate it with the XmlNamespaceDeclarations
// attribute.
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces
{
get { return this._namespaces; }
}
private XmlSerializerNamespaces _namespaces;
}
That's all to this class. Now, some objected to having an XmlSerializerNamespaces object somewhere within their classes; but as you can see, I neatly tucked it away in the default constructor and exposed a public property to return the namespaces.
Now, when it comes time to serialize the class, you would use the following code:
MyTypeWithNamespaces myType = new MyTypeWithNamespaces("myLabel", 42);
/******
OK, I just figured I could do this to make the code shorter, so I commented out the
below and replaced it with what follows:
// You have to use this constructor in order for the root element to have the right namespaces.
// If you need to do custom serialization of inner objects, you can use a shortened constructor.
XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces), new XmlAttributeOverrides(),
new Type[]{}, new XmlRootAttribute("MyTypeWithNamespaces"), "urn:Abracadabra");
******/
XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces),
new XmlRootAttribute("MyTypeWithNamespaces") { Namespace="urn:Abracadabra" });
// I'll use a MemoryStream as my backing store.
MemoryStream ms = new MemoryStream();
// This is extra! If you want to change the settings for the XmlSerializer, you have to create
// a separate XmlWriterSettings object and use the XmlTextWriter.Create(...) factory method.
// So, in this case, I want to omit the XML declaration.
XmlWriterSettings xws = new XmlWriterSettings();
xws.OmitXmlDeclaration = true;
xws.Encoding = Encoding.UTF8; // This is probably the default
// You could use the XmlWriterSetting to set indenting and new line options, but the
// XmlTextWriter class has a much easier method to accomplish that.
// The factory method returns a XmlWriter, not a XmlTextWriter, so cast it.
XmlTextWriter xtw = (XmlTextWriter)XmlTextWriter.Create(ms, xws);
// Then we can set our indenting options (this is, of course, optional).
xtw.Formatting = Formatting.Indented;
// Now serialize our object.
xs.Serialize(xtw, myType, myType.Namespaces);
Once you have done this, you should get the following output:
<MyTypeWithNamespaces>
<Label xmlns="urn:Whoohoo">myLabel</Label>
<Epoch>42</Epoch>
</MyTypeWithNamespaces>
I have successfully used this method in a recent project with a deep hierachy of classes that are serialized to XML for web service calls. Microsoft's documentation is not very clear about what to do with the publicly accesible XmlSerializerNamespaces member once you've created it, and so many think it's useless. But by following their documentation and using it in the manner shown above, you can customize how the XmlSerializer generates XML for your classes without resorting to unsupported behavior or "rolling your own" serialization by implementing IXmlSerializable.
It is my hope that this answer will put to rest, once and for all, how to get rid of the standard xsi and xsd namespaces generated by the XmlSerializer.
UPDATE: I just want to make sure I answered the OP's question about removing all namespaces. My code above will work for this; let me show you how. Now, in the example above, you really can't get rid of all namespaces (because there are two namespaces in use). Somewhere in your XML document, you're going to need to have something like xmlns="urn:Abracadabra" xmlns:w="urn:Whoohoo. If the class in the example is part of a larger document, then somewhere above a namespace must be declared for either one of (or both) Abracadbra and Whoohoo. If not, then the element in one or both of the namespaces must be decorated with a prefix of some sort (you can't have two default namespaces, right?). So, for this example, Abracadabra is the defalt namespace. I could inside my MyTypeWithNamespaces class add a namespace prefix for the Whoohoo namespace like so:
public MyTypeWithNamespaces
{
this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
new XmlQualifiedName(string.Empty, "urn:Abracadabra"), // Default Namespace
new XmlQualifiedName("w", "urn:Whoohoo")
});
}
Now, in my class definition, I indicated that the <Label/> element is in the namespace "urn:Whoohoo", so I don't need to do anything further. When I now serialize the class using my above serialization code unchanged, this is the output:
<MyTypeWithNamespaces xmlns:w="urn:Whoohoo">
<w:Label>myLabel</w:Label>
<Epoch>42</Epoch>
</MyTypeWithNamespaces>
Because <Label> is in a different namespace from the rest of the document, it must, in someway, be "decorated" with a namespace. Notice that there are still no xsi and xsd namespaces.
XmlSerializer sr = new XmlSerializer(objectToSerialize.GetType());
TextWriter xmlWriter = new StreamWriter(filename);
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add(string.Empty, string.Empty);
sr.Serialize(xmlWriter, objectToSerialize, namespaces);
This is the first of my two answers to the question.
If you want fine control over the namespaces - for example if you want to omit some of them but not others, or if you want to replace one namespace with another, you can do this using XmlAttributeOverrides.
Suppose you have this type definition:
// explicitly specify a namespace for this type,
// to be used during XML serialization.
[XmlRoot(Namespace="urn:Abracadabra")]
public class MyTypeWithNamespaces
{
// private fields backing the properties
private int _Epoch;
private string _Label;
// explicitly define a distinct namespace for this element
[XmlElement(Namespace="urn:Whoohoo")]
public string Label
{
set { _Label= value; }
get { return _Label; }
}
// this property will be implicitly serialized to XML using the
// member name for the element name, and inheriting the namespace from
// the type.
public int Epoch
{
set { _Epoch= value; }
get { return _Epoch; }
}
}
And this serialization pseudo-code:
var o2= new MyTypeWithNamespaces() { ..initializers...};
ns.Add( "", "urn:Abracadabra" );
XmlSerializer s2 = new XmlSerializer(typeof(MyTypeWithNamespaces));
s2.Serialize(System.Console.Out, o2, ns);
You would get something like this XML:
<MyTypeWithNamespaces xmlns="urn:Abracadabra">
<Label xmlns="urn:Whoohoo">Cimsswybclaeqjh</Label>
<Epoch>97</Epoch>
</MyTypeWithNamespaces>
Notice that there is a default namespace on the root element, and there is also a distinct namespace on the "Label" element. These namespaces were dictated by the attributes decorating the type, in the code above.
The Xml Serialization framework in .NET includes the possibility to explicitly override the attributes that decorate the actual code. You do this with the XmlAttributesOverrides class and friends. Suppose I have the same type, and I serialize it this way:
// instantiate the container for all attribute overrides
XmlAttributeOverrides xOver = new XmlAttributeOverrides();
// define a set of XML attributes to apply to the root element
XmlAttributes xAttrs1 = new XmlAttributes();
// define an XmlRoot element (as if [XmlRoot] had decorated the type)
// The namespace in the attribute override is the empty string.
XmlRootAttribute xRoot = new XmlRootAttribute() { Namespace = ""};
// add that XmlRoot element to the container of attributes
xAttrs1.XmlRoot= xRoot;
// add that bunch of attributes to the container holding all overrides
xOver.Add(typeof(MyTypeWithNamespaces), xAttrs1);
// create another set of XML Attributes
XmlAttributes xAttrs2 = new XmlAttributes();
// define an XmlElement attribute, for a type of "String", with no namespace
var xElt = new XmlElementAttribute(typeof(String)) { Namespace = ""};
// add that XmlElement attribute to the 2nd bunch of attributes
xAttrs2.XmlElements.Add(xElt);
// add that bunch of attributes to the container for the type, and
// specifically apply that bunch to the "Label" property on the type.
xOver.Add(typeof(MyTypeWithNamespaces), "Label", xAttrs2);
// instantiate a serializer with the overrides
XmlSerializer s3 = new XmlSerializer(typeof(MyTypeWithNamespaces), xOver);
// serialize
s3.Serialize(System.Console.Out, o2, ns2);
The result looks like this;
<MyTypeWithNamespaces>
<Label>Cimsswybclaeqjh</Label>
<Epoch>97</Epoch>
</MyTypeWithNamespaces>
You have stripped the namespaces.
A logical question is, can you strip all namespaces from arbitrary types during serialization, without going through the explicit overrides? The answer is YES, and how to do it is in my next response.