public void HttpOperationDescription_Return_Parameter_Matches_Void_Method() { OperationDescription od = GetOperationDescription(typeof(SimpleOperationsService), "ZeroInputsAndReturnsVoid"); HttpOperationDescription hod = od.ToHttpOperationDescription(); Assert.IsNotNull(hod, "Failed to create HttpOperationDescription"); HttpParameter returnParameter = hod.ReturnValue; Assert.IsNotNull(returnParameter, "Return parameter was null"); Assert.AreEqual(typeof(void), returnParameter.Type, "Return parameter type should have been void"); }
/// <summary> /// Called when the ordered collection of <see cref="HttpOperationHandler"/> instances is being created for /// the given <paramref name="operation"/>. Can be overridden in a derived class to customize the /// collection of <see cref="HttpOperationHandler"/> instances returned. /// </summary> /// <remarks> /// The base implemenation returns the standard response <see cref="HttpOperationHandler"/> instances for the given /// operation. /// </remarks> /// <param name="endpoint">The service endpoint.</param> /// <param name="operation"> /// The <see cref="HttpOperationDescription"/> for the given operation that the <see cref="HttpOperationHandler"/> /// instances will be associated with.</param> /// <returns> /// The ordered collection of <see cref="HttpOperationHandler"/> instances to use when handling /// <see cref="HttpResponseMessage"/> instances for the given operation. /// </returns> protected virtual Collection <HttpOperationHandler> OnCreateResponseHandlers(ServiceEndpoint endpoint, HttpOperationDescription operation) { if (endpoint == null) { throw Fx.Exception.ArgumentNull("endpoint"); } if (operation == null) { throw Fx.Exception.ArgumentNull("operation"); } Collection <HttpOperationHandler> responseHandlers = new Collection <HttpOperationHandler>(); List <HttpParameter> possibleContentParameters = new List <HttpParameter>(); HttpParameter returnValue = operation.ReturnValue; if (returnValue != null && IsPossibleResponseContentParameter(returnValue)) { possibleContentParameters.Add(returnValue); } foreach (HttpParameter parameter in operation.OutputParameters) { if (parameter != null && IsPossibleResponseContentParameter(parameter)) { possibleContentParameters.Add(returnValue); } } if (possibleContentParameters.Count > 1) { ThrowExceptionForMulitpleResponseContentParameters(possibleContentParameters, returnValue, operation.Name); } HttpParameter responseContentParameter = possibleContentParameters.Count == 1 ? possibleContentParameters[0] : returnValue; if (responseContentParameter != null && responseContentParameter.Type != TypeHelper.VoidType) { bool isReturnValue = responseContentParameter == returnValue; ValidateResponseContentParameter(responseContentParameter, isReturnValue, operation.Name); responseContentParameter.IsContentParameter = true; SetXmlAndJsonSerializers(operation, responseContentParameter, this.Formatters); } ResponseContentHandler responseContentHandler = new ResponseContentHandler(responseContentParameter, this.Formatters); responseHandlers.Add(responseContentHandler); return(responseHandlers); }
private static bool IsPossibleRequestContentParameter(HttpParameter parameter) { Fx.Assert(parameter != null, "The 'parameter' parameter should not be null."); if (parameter.IsContentParameter || HttpTypeHelper.GetHttpRequestOrContentInnerTypeOrNull(parameter.Type) != null) { return(true); } return(false); }
// Verifies that a HttpOperationDescription built from an OperationDescription // matches the given MethodInfo for return type, parameters, and attributes private void AssertHttpOperationDescriptionMatchesMethod(HttpOperationDescription hod, MethodInfo method) { Assert.IsNotNull(hod, "HttpOperationDescription was null"); Assert.AreEqual(hod.Name, method.Name, "Name mismatch"); HttpParameter returnParameter = hod.ReturnValue; if (!hod.ToOperationDescription().IsOneWay) { Assert.AreEqual(returnParameter.Type, method.ReturnType, "Return type mismatch"); } IList <HttpParameter> inputParameters = hod.InputParameters; ParameterInfo[] parameters = method.GetParameters().Where(p => !p.IsOut).ToArray(); Assert.AreEqual(parameters.Length, inputParameters.Count, "Input parameter count mismatch"); for (int i = 0; i < parameters.Length; ++i) { Assert.AreEqual(parameters[i].Name, inputParameters[i].Name, "Input parameter name mismatch"); Assert.AreEqual(parameters[i].ParameterType, inputParameters[i].Type, "Input parameter type mismatch"); } IList <HttpParameter> outputParameters = hod.OutputParameters; parameters = method.GetParameters().Where(p => p.IsOut).ToArray(); Assert.AreEqual(parameters.Length, outputParameters.Count, "Output parameter count mismatch"); for (int i = 0; i < parameters.Length; ++i) { Assert.AreEqual(parameters[i].Name, outputParameters[i].Name, "Output parameter name mismatch"); // ServiceModel removes the ByRef part Type t = parameters[i].ParameterType; if (t.HasElementType && t.IsByRef) { t = t.GetElementType(); } Assert.AreEqual(t, outputParameters[i].Type, "Output parameter type mismatch"); } IEnumerable <Attribute> hodAttributes = hod.Attributes; IEnumerable <Attribute> methodAttributes = method.GetCustomAttributes(false).Cast <Attribute>().ToArray(); foreach (Attribute a in methodAttributes) { if (!hodAttributes.Contains(a)) { Assert.Fail("Did not find attribute " + a.GetType().Name + " on method " + method.Name); } } }
public void HttpOperationDescription_Return_Parameter_Matches_Method() { OperationDescription od = GetOperationDescription(typeof(SimpleOperationsService), "OneInputAndReturnValue"); HttpOperationDescription hod = od.ToHttpOperationDescription(); Assert.IsNotNull(hod, "Failed to create HttpOperationDescription"); HttpParameter returnParameter = hod.ReturnValue; Assert.IsNotNull(returnParameter, "Return parameter was null"); Assert.AreEqual(typeof(string), returnParameter.Type, "Return parameter type should have been string"); Assert.AreEqual("OneInputAndReturnValueResult", returnParameter.Name, "Return parameter name match operation + Result"); }
public void HttpOperationDescription_Unsynchronized_ReturnValue_Setter() { HttpOperationDescription hod = new HttpOperationDescription(); HttpParameter returnValue = new HttpParameter("TheReturn", typeof(string)); hod.ReturnValue = returnValue; Assert.AreSame(returnValue, hod.ReturnValue, "Failed to set return value"); hod.ReturnValue = null; Assert.IsNull(hod.ReturnValue, "Failed to reset return value"); }
private static bool IsValidContentType(HttpParameter requestContentParameter) { Fx.Assert(requestContentParameter != null, "The 'requestContentParameter' parameter should not be null."); foreach (Type invalidType in invalidContentTypes) { if (invalidType.IsAssignableFrom(requestContentParameter.Type)) { return(false); } } return(true); }
private static void ValidateRequestContentParameter(HttpParameter requestContentParameter, string operationName) { Fx.Assert(requestContentParameter != null, "The 'requestContentParameter' parameter should not be null."); Fx.Assert(operationName != null, "The 'operationName' parameter should not be null."); if (!IsValidContentType(requestContentParameter) || HttpTypeHelper.HttpResponseMessageType.IsAssignableFrom(requestContentParameter.Type)) { throw Fx.Exception.AsError( new InvalidOperationException( SR.InvalidRequestContentParameter( operationName, requestContentParameter.Type.Name, httpOperationHandlerFactoryType.Name))); } }
public void HttpOperationDescription_Update_ReturnValue_From_Incomplete_HttpOperationDescription() { OperationDescription od = GetOperationDescription(typeof(SimpleOperationsService), "OneInputAndReturnValue"); MessagePartDescription mpd = od.Messages[1].Body.ReturnValue; HttpOperationDescription hod = od.ToHttpOperationDescription(); HttpParameter hpd = hod.ReturnValue; // Clear out all of Messages[] od.Messages.Clear(); Assert.IsNull(hod.ReturnValue, "ReturnValue should be null with no backing Messages[1]"); // Setting a valid ReturnValue should auto-create Messages[1] hod.ReturnValue = hpd; Assert.IsNotNull(hod.ReturnValue, "ReturnValue was not set"); Assert.AreSame(hpd.MessagePartDescription, hod.ReturnValue.MessagePartDescription, "ReturnValue not as expected"); Assert.AreEqual(2, od.Messages.Count, "Setting ReturnValue should have created Messages[1]"); }
public void HttpOperationDescription_Update_OutputParameters_From_Incomplete_HttpOperationDescription() { OperationDescription od = GetOperationDescription(typeof(SimpleOperationsService), "OneInputOneOutputAndReturnValue"); MessagePartDescription mpd = od.Messages[1].Body.Parts[0]; // output parameter 1 in the MPD HttpOperationDescription hod = od.ToHttpOperationDescription(); IList <HttpParameter> hpdColl = hod.OutputParameters; HttpParameter hpd = hpdColl[0]; // Zap the Messages[] od.Messages.Clear(); // Zapping the backing Messages should have rendered the input collection empty Assert.AreEqual(0, hpdColl.Count, "Resetting Messages did not reset count"); Assert.AreEqual(0, hod.InputParameters.Count, "Resetting Messages did not reset count in HOD"); // Mutating the OutputParameter collection should auto-create the both in and out Messages hpdColl.Add(hpd); Assert.AreEqual(2, od.Messages.Count, "Messages[1] was not autocreated"); Assert.AreEqual(1, hpdColl.Count, "Creating Messages did not set count"); Assert.AreEqual(1, hod.OutputParameters.Count, "Creating Messages did not set count in HOD"); }
/// <summary> /// Called when the ordered collection of <see cref="HttpOperationHandler"/> instances is being created for /// the given <paramref name="operation"/>. Can be overridden in a derived class to customize the /// collection of <see cref="HttpOperationHandler"/> instances returned. /// </summary> /// <remarks> /// The base implemenation returns the standard request <see cref="HttpOperationHandler"/> instances for the given /// operation. /// </remarks> /// <param name="endpoint">The service endpoint.</param> /// <param name="operation">The description of the service operation.</param> /// <returns> /// The ordered collection of <see cref="HttpOperationHandler"/> instances to use when handling /// <see cref="HttpRequestMessage"/> instances for the given operation. /// </returns> protected virtual Collection <HttpOperationHandler> OnCreateRequestHandlers(ServiceEndpoint endpoint, HttpOperationDescription operation) { if (endpoint == null) { throw Fx.Exception.ArgumentNull("endpoint"); } if (operation == null) { throw Fx.Exception.ArgumentNull("operation"); } Collection <HttpOperationHandler> requestHandlers = new Collection <HttpOperationHandler>(); HttpMethod method = operation.GetHttpMethod(); UriTemplate uriTemplate = operation.GetUriTemplate(); string[] uriTemplateParameterNames = uriTemplate.PathSegmentVariableNames.Concat(uriTemplate.QueryValueVariableNames).ToArray(); if (uriTemplateParameterNames.Length > 0) { requestHandlers.Add(new UriTemplateHandler(endpoint.Address.Uri, uriTemplate)); } if (method != HttpMethod.Get && method != HttpMethod.Head) { HttpParameter requestContentParameter = GetRequestContentHandler(operation, uriTemplateParameterNames); if (requestContentParameter != null) { requestContentParameter.IsContentParameter = true; requestHandlers.Add(new RequestContentHandler(requestContentParameter, this.Formatters)); SetXmlAndJsonSerializers(operation, requestContentParameter, this.Formatters); } } return(requestHandlers); }
private static void SetXmlAndJsonSerializers(HttpOperationDescription operation, HttpParameter httpParameter, MediaTypeFormatterCollection formatters) { Fx.Assert(operation != null, "The 'operation' parameter should not be null."); Fx.Assert(httpParameter != null, "The 'httpParameter' parameter should not be null."); Fx.Assert(formatters != null, "The 'formatters' parameter should not be null."); Type contentType = HttpTypeHelper.GetHttpInnerTypeOrNull(httpParameter.Type) ?? httpParameter.Type; if (contentType != typeof(JsonValue) && !HttpTypeHelper.IsHttp(contentType)) { SetSerializerForXmlFormatter(operation, contentType, formatters); SetSerializerForJsonFormatter(operation, contentType, httpParameter.Name, formatters); } }
private static void ThrowExceptionForMulitpleResponseContentParameters(List <HttpParameter> possibleContentParameters, HttpParameter returnValue, string operationName) { Fx.Assert(possibleContentParameters != null, "The 'possibleContentParameters' parameter should not be null."); Fx.Assert(returnValue != null, "The 'returnValue' parameter should not be null."); Fx.Assert(operationName != null, "The 'operationName' parameter should not be null."); string errorMessage = SR.MultipleResponseContentParameters( httpOperationHandlerFactoryType.Name, operationName, possibleContentParameters.Count); StringBuilder stringBuilder = new StringBuilder(errorMessage); foreach (HttpParameter parameter in possibleContentParameters) { string parameterMessage = null; if (parameter.IsContentParameter) { if (parameter == returnValue) { parameterMessage = SR.ReturnValueWithIsContentParameterSet( HttpParameter.IsContentParameterPropertyName, bool.TrueString); } else { parameterMessage = SR.ResponseParameterWithIsContentParameterSet( parameter.Name, HttpParameter.IsContentParameterPropertyName, bool.TrueString); } } else { if (parameter == returnValue) { parameterMessage = SR.ReturnValueWithContentType( parameter.Type.Name); } else { parameterMessage = SR.ResponseParameterWithContentType( parameter.Name, parameter.Type.Name); } } stringBuilder.Append(Environment.NewLine); stringBuilder.Append(parameterMessage); } throw Fx.Exception.AsError(new InvalidOperationException(stringBuilder.ToString())); }
public static OperationDescription GetEquivalentOperationDescription(OperationDescription operation) { Fx.Assert(operation != null, "OperationDescription cannnot be null"); OperationDescription copy = CreateEmptyOperationDescription(operation); HttpOperationDescription httpDescription = copy.ToHttpOperationDescription(); HttpOperationDescription originalHttpDescription = operation.ToHttpOperationDescription(); UriTemplate template = originalHttpDescription.GetUriTemplate(); List <string> templateVariables = new List <string>(template.PathSegmentVariableNames.Concat(template.QueryValueVariableNames)); IEnumerable <HttpParameter> originalRequestBodyParameters = originalHttpDescription.InputParameters.Where(param => param.IsContentParameter); IEnumerable <HttpParameter> originalResponseBodyParameters = originalHttpDescription.OutputParameters.Where(param => param.IsContentParameter); IEnumerable <HttpParameter> originalUriTemplateParameters = originalHttpDescription.InputParameters.Where( (param) => { foreach (string templateVariable in templateVariables) { if (string.Equals(templateVariable, param.Name, StringComparison.OrdinalIgnoreCase)) { return(true); } } return(false); }); httpDescription.ReturnValue = originalHttpDescription.ReturnValue; // add UriTemplate parameters foreach (HttpParameter parameter in originalUriTemplateParameters) { httpDescription.InputParameters.Add(parameter); } // add body parameters foreach (HttpParameter parameter in originalRequestBodyParameters) { httpDescription.InputParameters.Add(parameter); } int index = httpDescription.InputParameters.Count; int requestBodyParametersCount = originalRequestBodyParameters.Count <HttpParameter>(); int responseBodyParametersCount = originalResponseBodyParameters.Count <HttpParameter>(); if (requestBodyParametersCount == 0 || responseBodyParametersCount == 0) { // Special case if any input parameter is HttpRequestMessage or HttpResponseMessage foreach (HttpParameter inputParameter in originalHttpDescription.InputParameters) { if (requestBodyParametersCount == 0 && originalHttpDescription.GetHttpMethod() != HttpMethod.Get && httpRequestMessageType.IsAssignableFrom(inputParameter.Type)) { // add the HttpRequestmessage as a body parameter of type Message HttpParameter parameter = new HttpParameter(new MessagePartDescription(inputParameter.Name, string.Empty) { Type = typeof(Message), Index = index++ }); httpDescription.InputParameters.Add(parameter); } if (!operation.IsOneWay && responseBodyParametersCount == 0 && httpResponseMessageType.IsAssignableFrom(inputParameter.Type)) { // add the HttpResponsemessage as a return value of type Message httpDescription.ReturnValue = new HttpParameter(new MessagePartDescription(inputParameter.Name, string.Empty) { Type = typeof(Message) }); } } } foreach (HttpParameter parameter in originalResponseBodyParameters) { // cannot do a byRef comparison here if (parameter.Type != originalHttpDescription.ReturnValue.Type || !string.Equals(parameter.Name, originalHttpDescription.ReturnValue.Name, StringComparison.OrdinalIgnoreCase)) { httpDescription.OutputParameters.Add(parameter); } } if (responseBodyParametersCount == 0) { foreach (HttpParameter outputParameter in originalHttpDescription.OutputParameters) { // special case HttpResponseMessage when it is set as an out parameter if (httpResponseMessageType.IsAssignableFrom(outputParameter.Type)) { httpDescription.ReturnValue = new HttpParameter(new MessagePartDescription(outputParameter.Name, string.Empty) { Type = typeof(Message) }); } } } if (templateVariables.Count > originalUriTemplateParameters.Count <HttpParameter>()) { // this means that we have some UriTemplate variables that are not explicitly bound to an input parameter foreach (HttpParameter parameter in originalUriTemplateParameters) { templateVariables.Remove(parameter.Name); } foreach (string variable in templateVariables) { HttpParameter parameter = new HttpParameter(new MessagePartDescription(variable, operation.DeclaringContract.Namespace) { Type = typeof(string), Index = index++ }); httpDescription.InputParameters.Add(parameter); } } return(httpDescription.ToOperationDescription()); }