Bu cevap yolu çok geç! Ama belki diğer geliştiriciler için yararlıdır ;-). Bu problemi çözmek için relfection kullandım, çünkü otomatik olması gerekiyordu.
Statik yöntem CreateMessageType çağrılmalıdır. schemaLocation özelliğini içeren NOT seri hale getirilmiş sınıf olmalıdır. Bu yöntem, asal (Dynamic adlı) kullanarak yeni bir tür döndürür, ancak schemaLocation özelliklerini ekler ve XmlRootAttribute öğesinin ElementName özelliğini ayarlar.
türü oluşturma sonra yansıma yeniden özellikleri bir obje yaratması ve ayarlamak için kullanılmalıdır.
kod xxx oldukça ağrı gibi görünüyor, ama bir cazibe gibi çalışır!
/// <summary>Copying the attributes of a type to a new type</summary>
private static void copyAttributes<TMessage>(TypeBuilder dynamictype)
{
try
{
//Iterate over all attributes of the TMessage class and copy these to the new type
IList<CustomAttributeData> attributes = CustomAttributeData.GetCustomAttributes(typeof(TMessage));
if (attributes != null)
{
foreach (CustomAttributeData attribute in attributes)
{
List<object> constructorarguments = new List<object>();
if (attribute.ConstructorArguments != null)
{
foreach (CustomAttributeTypedArgument argument in attribute.ConstructorArguments)
{
constructorarguments.Add(argument.Value);
}
}
List<FieldInfo> namedfields = new List<FieldInfo>();
List<object> namedfieldarguments = new List<object>();
List<PropertyInfo> namedproperties = new List<PropertyInfo>();
List<object> namedpropertyarguments = new List<object>();
if (attribute.NamedArguments != null)
{
//Iterate over all named arguments
foreach (CustomAttributeNamedArgument argument in attribute.NamedArguments)
{
//Check which type of argument is found
if (argument.MemberInfo is FieldInfo)
{
FieldInfo field = argument.MemberInfo as FieldInfo;
namedfields.Add(field);
namedfieldarguments.Add(argument.TypedValue.Value);
}
else if (argument.MemberInfo is PropertyInfo)
{
PropertyInfo property = argument.MemberInfo as PropertyInfo;
namedproperties.Add(property);
namedpropertyarguments.Add(argument.TypedValue.Value);
}
}
}
//Check if the current attribute is of type XmlRoot.
//In this case the ElementName or TypeName property must also be set
if (attribute.Constructor.DeclaringType.Equals(typeof(XmlRootAttribute)))
{
namedproperties.Add(typeof(XmlRootAttribute).GetProperty("ElementName"));
namedpropertyarguments.Add(typeof(TMessage).Name);
}
//Build the copy of the parent attribute
CustomAttributeBuilder copyattributebuilder = new CustomAttributeBuilder(
attribute.Constructor,
constructorarguments.ToArray(),
namedproperties.ToArray(),
namedpropertyarguments.ToArray(),
namedfields.ToArray(),
namedfieldarguments.ToArray());
//Add the attribute to the dynamic type
dynamictype.SetCustomAttribute(copyattributebuilder);
}
}
}
catch (Exception exception)
{
throw new ApplicationException("Unable to copy attribute from parent type", exception);
}
}
/// <summary>Create dynamic type for an operation message which includes the types for serialization</summary>
/// <returns>Returns dynamic type</returns>
public static Type CreateMessageType<TMessage>()
{
try
{
AssemblyBuilder assemblybuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run);
ModuleBuilder modulebuilder = assemblybuilder.DefineDynamicModule(Guid.NewGuid().ToString(), false);
//Create type based on an unique so that it does not conflict with the OperationMessage classname
TypeBuilder typebuilder = modulebuilder.DefineType(typeof(TMessage).Name + "Dynamic", TypeAttributes.Public | TypeAttributes.Class);
//Set original message type as parent of the new dynamic type
typebuilder.SetParent(typeof(TMessage));
//Copy attributes from TMessage paren type to the dynamic type
WMQXMLMessageTypeFactory.copyAttributes<TMessage>(typebuilder);
//Create the xsi:schemaLocation property
CustomAttributeBuilder attributebuilder = new CustomAttributeBuilder(
typeof(XmlAttributeAttribute).GetConstructor(new Type[] { typeof(string) }),
new object[] { "schemaLocation" },
new PropertyInfo[] { typeof(XmlAttributeAttribute).GetProperty("Namespace") },
new object[] { XmlSchema.InstanceNamespace });
FieldBuilder schemalocationfieldbuilder = typebuilder.DefineField("SchemaLocation", typeof(string), FieldAttributes.Public);
schemalocationfieldbuilder.SetCustomAttribute(attributebuilder);
return typebuilder.CreateType();
}
catch (Exception exception)
{
throw new ApplicationException("Unable to create XML message type", exception);
}
}
aşağıdaki Ben nesneyi
Type type = WMQXMLMessageTypeFactory.CreateMessageType<TenantRequest>();
MetaData metadata = new MetaData();
metadata.ID = Guid.NewGuid().ToString();
metadata.Created = DateTime.Now;
metadata.Application = new schemasdev.local.tenant.Application();
metadata.Application.Name = "Publish Tenant";
metadata.Application.Core = ApplicationCore.PropertySystem;
NewOperation newoperation = new NewOperation();
newoperation.Tenant = new Tenant();
newoperation.Tenant.Code = "001";
newoperation.Tenant.Name = "Mister X";
object request = type.GetConstructor(new Type[0]).Invoke(new object[0]);
(request as TenantRequest).MetaData = metadata;
(request as TenantRequest).New = newoperation;
//Setting the schema location property
type.InvokeMember("SchemaLocation", System.Reflection.BindingFlags.SetField, null, request, new object[] { "http://schemasdev.local/2012-01/Tenant/1.0/Tenant.xsd" });
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(type);
stream = new System.IO.MemoryStream();
serializer.Serialize(stream, request);
Console.WriteLine(UTF8Encoding.UTF8.GetString(stream.ToArray()));
oluşturmak için kullanılan kod Ve sonunda mükemmel çıktı:
<?xml version="1.0"?>
<TenantRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:schemaLocation="http://schemasdev.local/2012-01/Tenant/1.0/Tenant.xsd" xmlns="http://schemasdev.local/2012-01/Tenant/1.0">
<MetaData xmlns="http://schemasdev.local/2012-01/Messaging/1.0">
<ID>b59938fd-8e68-4927-87da-6d92c609f159</ID>
<Application>
<Name>Publish Tenant</Name>
<Core>PropertySystem</Core>
</Application>
<Created>2012-02-20T10:07:54.645424+01:00</Created>
</MetaData>
<New>
<Tenant>
<Code>001</Code>
<Name>Mister X</Name>
</Tenant>
</New>
</TenantRequest>
Mükemmel teşekkürler! –
ŞemaKonum ne için ayarlandı? XSD.EXE'nin kullandığı yer, xsi: schemaLocation kullanıcısının kullanıcının bulması gereken web'de bulunma olasılığı düşüktür. –
@John: Belki xsd dosyasındaki değeri belirtmek için bir seçenek var mı? – dtb