private static void CreatePreflightOperation(OperationDescription operation, string originalUriTemplateStr, string originalMethod, ContractDescription contract, out OperationDescription preflightOperation, out PreflightOperationBehavior preflightOperationBehavior) { var originalUriTemplate = new UriTemplate(originalUriTemplateStr); preflightOperation = new OperationDescription(operation.Name + "_preflight", contract); //First the input message MessageDescription inputMessage = new MessageDescription(operation.Messages[0].Action + "_preflight", MessageDirection.Input); preflightOperation.Messages.Add(inputMessage); //We need to mirror the input parameters in the URI template //First any variables in the path if (originalUriTemplate.PathSegmentVariableNames != null && originalUriTemplate.PathSegmentVariableNames.Count > 0) { foreach (string uriParameter in originalUriTemplate.PathSegmentVariableNames) { inputMessage.Body.Parts.Add(new MessagePartDescription(uriParameter, "") { Type = typeof(string) }); } } //Next any in the querystring if (originalUriTemplate.QueryValueVariableNames != null && originalUriTemplate.QueryValueVariableNames.Count > 0) { foreach (string uriParameter in originalUriTemplate.QueryValueVariableNames) { inputMessage.Body.Parts.Add(new MessagePartDescription(uriParameter, "") { Type = typeof(string) }); } } //Now the output message, we only need the CORS headers in reality MessageDescription outputMessage = new MessageDescription(operation.Messages[1].Action + "_preflight", MessageDirection.Output); //outputMessage.Body.ReturnValue = new MessagePartDescription(preflightOperation.Name + "Return", contract.Namespace) { Type = typeof(Message) }; preflightOperation.Messages.Add(outputMessage); WebInvokeAttribute wia = new WebInvokeAttribute(); wia.UriTemplate = originalUriTemplate.ToString(); wia.Method = "OPTIONS"; //TODO:TEST //wia.BodyStyle = WebMessageBodyStyle.WrappedRequest; preflightOperation.Behaviors.Add(wia); preflightOperation.Behaviors.Add(new DataContractSerializerOperationBehavior(preflightOperation)); preflightOperationBehavior = new PreflightOperationBehavior(preflightOperation); preflightOperationBehavior.AddAllowedMethod(originalMethod); preflightOperation.Behaviors.Add(preflightOperationBehavior); }
private void AddPreflightOperation(OperationDescription operation, Dictionary <string, PreflightOperationBehavior> uriTemplates) { if (operation.Behaviors.Find <WebGetAttribute>() != null || operation.IsOneWay)//|| operation.DeclaringContract.Operations.Any(o => o.Behaviors.Find<PreflightOperationBehavior>() != null)) { // no need to add preflight operation for GET requests, no support for 1-way messages return; } string originalUriTemplate; WebInvokeAttribute originalWia = operation.Behaviors.Find <WebInvokeAttribute>(); if (originalWia != null && originalWia.UriTemplate != null) { originalUriTemplate = NormalizeTemplate(originalWia.UriTemplate); } else { originalUriTemplate = operation.Name; } string originalMethod = originalWia != null && originalWia.Method != null ? originalWia.Method : "POST"; if (uriTemplates.ContainsKey(originalUriTemplate)) { // there is already an OPTIONS operation for this URI, we can reuse it PreflightOperationBehavior operationBehavior = uriTemplates[originalUriTemplate]; operationBehavior.AddAllowedMethod(originalMethod); } else { ContractDescription contract = operation.DeclaringContract; OperationDescription preflightOperation; PreflightOperationBehavior preflightOperationBehavior; CreatePreflightOperation(operation, originalUriTemplate, originalMethod, contract, out preflightOperation, out preflightOperationBehavior); uriTemplates.Add(originalUriTemplate, preflightOperationBehavior); //contract.Operations.Add(preflightOperation); contract.Operations.Insert(0, preflightOperation); } }