gpt4 book ai didi

wcf - 在运行时创建 WCF 服务

转载 作者:行者123 更新时间:2023-12-02 17:50:36 27 4
gpt4 key购买 nike

我们将根据在运行时读取的元数据构建 Web 服务。我指的是整个 Web 服务:签名、契约(Contract)和实现。

我从这里看到了两条主要路径。

第一个路径是您生成代码。要么以字符串形式生成 C# 代码并即时编译,要么更优雅(更复杂)地发出 MSIL 代码。这样您就拥有了 WCF 代码,WCF 将负责从中生成 WSDL。

第二条路径是使用通用服务。具有接受所有内容的操作 Message Process(Message) 的服务。我们仍然希望将该服务公开为“正常”服务,因此我需要在某处使用 WSDL。如何创建 WSDL?我考虑过使用 System.ServiceModel.Description,直到我意识到在内心深处,这个 API 取决于具体类型。使用这种方法,我们将没有任何数据契约类型,并且可以动态处理 XML,使用元数据来解释它。所以我们需要以某种方式生成 WSDL。这是一个疯狂的想法吗? WSDL 有相当复杂的规范...

第三种选择是使用混合方法,发射类型只是为了创建签名,但使用非发射代码(反射(reflect)发射类型)实现服务。很奇怪,但可能比手工制作 WSDL 更简单...

建议?

最佳答案

做起来很痛苦,但对于发射类型来说是可能的。创建您的 .svc 并将其指向您的自定义 ServiceHostFactory:

<%@ ServiceHost Language="C#" Debug="true" Factory="Foo.FooServiceHostFactory" %>

[ServiceContract]
public class FooService { }

您的 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);
}

}在 ServiceHostFactory 中,您定义行为以及元数据,因此您的行为需要实现 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 中调用它(警告:它是演示代码)

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);
}
}

更新:我写了一个简单的例子,它可用here .

关于wcf - 在运行时创建 WCF 服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8864296/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com