고통은 있지만 방출 유형이 가능합니다. 당신의 SVC는 만들기 및 사용자 정의 ServiceHostFactory에 그것을 가리 킵니다 : 당신이 당신의 운영 계약, 그것으로 이동 유형 등을 생성 할 경우
이
<%@ ServiceHost Language="C#" Debug="true" Factory="Foo.FooServiceHostFactory" %>
[ServiceContract]
public class FooService { }
귀하의 ServiceHostFactory은 다음 ServiceHostFactory에서
public class FooServiceHostFactory : ServiceHostFactory {
public override System.ServiceModel.ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses) {
ServiceHost serviceHost = new FooServiceHost(baseAddresses);
serviceHost.AddDefaultEndpoints();
GenerateServiceOperations(serviceHost);
return serviceHost;
}
private void GenerateServiceOperations(ServiceHost serviceHost) {
var methodNames = new[] {
new { Name = "Add" },
new { Name = "Subtract" },
new { Name = "Multiply" }
};
foreach (var method in methodNames) {
foreach (var endpoint in serviceHost.Description.Endpoints) {
var contract = endpoint.Contract;
var operationDescription = new OperationDescription("Operation" + method.Name, contract);
var requestMessageDescription = new MessageDescription(string.Format("{0}{1}/Operation{2}", contract.Namespace, contract.Name, method.Name), MessageDirection.Input);
var responseMessageDescription = new MessageDescription(string.Format("{0}{1}/Operation{2}Response", contract.Namespace, contract.Name, method.Name), MessageDirection.Output);
var elements = new List<FooDataItem>();
elements.Add(new FooDataItem { Name = "X", DataType = typeof(int) });
elements.Add(new FooDataItem { Name = "Y", DataType = typeof(int) });
//note: for a complex type it gets more complicated, but the same idea using reflection during invoke()
//object type = TypeFactory.CreateType(method.Name, elements);
//var arrayOfType = Array.CreateInstance(type.GetType(), 0);
//var parameter = new MessagePartDescription(method.Name + "Operation", contract.Namespace);
//parameter.Type = arrayOfType.GetType();
//parameter.Index = 0;
//requestMessageDescription.Body.Parts.Add(parameter);
var retVal = new MessagePartDescription("Result", contract.Namespace);
retVal.Type = typeof(int);
responseMessageDescription.Body.ReturnValue = retVal;
int indexer = 0;
foreach (var element in elements) {
var parameter = new MessagePartDescription(element.Name, contract.Namespace);
parameter.Type = element.DataType;
parameter.Index = indexer++;
requestMessageDescription.Body.Parts.Add(parameter);
}
operationDescription.Messages.Add(requestMessageDescription);
operationDescription.Messages.Add(responseMessageDescription);
operationDescription.Behaviors.Add(new DataContractSerializerOperationBehavior(operationDescription));
operationDescription.Behaviors.Add(new FooOperationImplementation());
contract.Operations.Add(operationDescription);
}
}
}
protected override System.ServiceModel.ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) {
return base.CreateServiceHost(serviceType, baseAddresses);
}
} 당신 메타 데이터와 함께 동작을 정의하면 IOperationBehavior 및 IOperationInvoker를 구현하거나 (별도로 구현할 수 있음) 다음과 같이 표시해야합니다.
public class FooOperationImplementation : IOperationBehavior, IOperationInvoker {
OperationDescription operationDescription;
DispatchOperation dispatchOperation;
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) {
}
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) {
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) {
this.operationDescription = operationDescription;
this.dispatchOperation = dispatchOperation;
dispatchOperation.Invoker = this;
}
public void Validate(OperationDescription operationDescription) {
}
public object[] AllocateInputs() {
return new object[2];
}
public object Invoke(object instance, object[] inputs, out object[] outputs) {
//this would ALL be dynamic as well depending on how you are creating your service
//for example, you could keep metadata in the database and then look it up, etc
outputs = new object[0];
switch (operationDescription.Name) {
case "OperationAdd":
return (int)inputs[0] + (int)inputs[1];
case "OperationSubtract":
return (int)inputs[0] - (int)inputs[1];
case "OperationMultiply":
return (int)inputs[0] * (int)inputs[1];
default:
throw new NotSupportedException("wtf");
}
}
public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state) {
throw new NotImplementedException("Method is not asynchronous.");
}
public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result) {
throw new NotImplementedException("Method is not asynchronous.");
}
public bool IsSynchronous {
get { return true; }
}
복잡한 유형의 경우 여기에서 질문의 루트 인 판단 호를해야합니다. 유형을 내보내는 방법입니다. 여기에 예제가 있지만, 당신이보기에 어떤 방식 으로든 그것을 할 수 있습니다. 내 ServiceHostFactory이 전화 해요 내가 빠른 예를 썼다는 here로 볼 수 있습니다 : :
static public class TypeFactory {
static object _lock = new object();
static AssemblyName assemblyName;
static AssemblyBuilder assemblyBuilder;
static ModuleBuilder module;
static TypeFactory() {
lock (_lock) {
assemblyName = new AssemblyName();
assemblyName.Name = "FooBarAssembly";
assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
module = assemblyBuilder.DefineDynamicModule("FooBarModule");
}
}
static public object CreateType(string typeName, List<FooDataItem> elements) {
TypeBuilder typeBuilder = module.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class);
foreach(var element in elements) {
string propertyName = element.Name;
Type dataType = element.DataType;
FieldBuilder field = typeBuilder.DefineField("_" + propertyName, dataType, FieldAttributes.Private);
PropertyBuilder property =
typeBuilder.DefineProperty(propertyName,
PropertyAttributes.None,
dataType,
new Type[] { dataType });
MethodAttributes GetSetAttr =
MethodAttributes.Public |
MethodAttributes.HideBySig;
MethodBuilder currGetPropMthdBldr =
typeBuilder.DefineMethod("get_value",
GetSetAttr,
dataType,
Type.EmptyTypes);
ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator();
currGetIL.Emit(OpCodes.Ldarg_0);
currGetIL.Emit(OpCodes.Ldfld, field);
currGetIL.Emit(OpCodes.Ret);
MethodBuilder currSetPropMthdBldr =
typeBuilder.DefineMethod("set_value",
GetSetAttr,
null,
new Type[] { dataType });
ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
currSetIL.Emit(OpCodes.Ldarg_0);
currSetIL.Emit(OpCodes.Ldarg_1);
currSetIL.Emit(OpCodes.Stfld, field);
currSetIL.Emit(OpCodes.Ret);
property.SetGetMethod(currGetPropMthdBldr);
property.SetSetMethod(currSetPropMthdBldr);
}
Type generetedType = typeBuilder.CreateType();
return Activator.CreateInstance(generetedType);
}
}
업데이트 (경고는 데모 코드이다).
실례가 있습니까? – Beats
훌륭합니다, 대단히 감사합니다. – Beats