이 답변이 너무 늦었입니다! 그러나 다른 개발자에게 유용 할 수도 있습니다 ;-). 이 문제를 해결하기 위해 자동화를해야했기 때문에 relfection을 사용했습니다.
정적 메서드 CreateMessageType을 호출해야합니다. schemaLocation 속성을 포함하지 않는 직렬화 된 클래스 여야합니다. 이 메서드는 부모 (이름이 Dynamic)를 사용하여 새 유형을 반환하지만 schemaLocation 속성을 추가하고 ElementName 속성을 XmlRootAttribute로 설정합니다.
형식을 만든 후에는 반사를 다시 사용하여 개체를 만들고 속성을 설정해야합니다.
코드는 xxx에서 상당히 고통 스럽지만 매력처럼 작동합니다!
/// <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);
}
}
다음 내가 객체
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()));
를 만드는 데 사용되는 코드 그리고 결국 완벽한 출력 :
<?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>
감사합니다. –
schemaLocation을 어떻게 설정합니까? XSD.EXE에서 사용 된 위치는 웹에서 사용 가능하지 않으므로 xsi : schemaLocation 사용자가 찾아야합니다. –
@ John : 아마도 xsd 파일의 값을 지정하는 옵션이 있습니까? – dtb