Here are the examples of the csharp api Neon.Xunit.XunitExtensions.ErrorWriter.Error(string) taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.
1 Examples
19
Source : XunitExtensions.ValidateController.cs
with Apache License 2.0
from nforgeio
with Apache License 2.0
from nforgeio
public static void ValidateController<TServiceController>(this IGeneratedServiceClient client)
{
// Verify that the schema for the generated code is compatable with this
// version of the validator. We currently require schema=1.
var versionFields = client.GeneratorVersion.Split(':');
if (versionFields.Length != 2 || versionFields[1] != "1")
{
throw new IncompatibleServiceException($"The generated service client code is not compatible with this version of the validator. Consider upgrading to the latest Neon packages and rebuilding your service clients.");
}
// The idea here is to construct two dictionaries that map method signatures
// [MethodInfo] instances. One dictionary will do this for [TServiceImplementation]
// and the other one for the [client] preplaceded.
//
// The method signature will be formatted like:
//
// HTTPMethod["RouteTemplate"]: ReturnType (Param0Type, Param1Type,...)
//
// Note that we're only going to include parameters from the client that
// are tagged by [GeneratedParam]. The remaining parameters are client
// specific, like timeout or CancellationToken.
//
// We're also going to use the request route template (in brackets) rather
// than the method name (because the names may differ).
//
// We'll use these dictionaries to ensure that both the service controller
// and the generated service client implement the same methods and then
// we'll go back and verify the details for each matching method.
//
// NOTE: By default, we replacedume that all public non-static service controller
// methods will be validated against the generated service client. In rare
// situations, it may be useful to have service controller endpoint that are
// not covered by the generated clients. In these situations, you may
// tag these methods with [Neon.Common.ModelGen.NoValidation] and the those
// methods will be ignored.
var controllerMethods = new Dictionary<string, MethodInfo>();
var clientMethods = new Dictionary<string, MethodInfo>();
var controllerType = typeof(TServiceController);
var clientType = client.GetType();
var errors = new ErrorWriter();
// Ensure that the service controller and client route templates match.
var generatedClientAttribute = clientType.GetCustomAttribute<GeneratedClientAttribute>();
var controllerRouteAttribute = controllerType.GetCustomAttribute<Microsoft.AspNetCore.Mvc.RouteAttribute>();
if (generatedClientAttribute == null)
{
errors.Error($"[{clientType.Name}] must be tagged with a [GeneratedClient] attribute.");
}
if (controllerRouteAttribute == null)
{
errors.Error($"[{controllerType.Name}] must be tagged with a [Route] attribute.");
}
if (generatedClientAttribute != null && controllerRouteAttribute != null)
{
if (generatedClientAttribute.RouteTemplate != controllerRouteAttribute.Template)
{
errors.Error($"[{controllerType.Name}] has [Route(\"{controllerRouteAttribute.Template}\")] which does not match [{clientType.Name}] client's [Route(\"{generatedClientAttribute.RouteTemplate}\")].");
}
}
// Load the controller methods.
foreach (var method in controllerType.GetMethods(BindingFlags.Public | BindingFlags.Instance))
{
var noValidationAttribute = method.GetCustomAttribute<NoControllerValidationAttribute>();
if (noValidationAttribute != null)
{
continue;
}
if (method.IsSpecialName)
{
// Ignore property setters, getters, etc.
continue;
}
if (method.DeclaringType != controllerType && method.GetCustomAttribute<ControllerValidationAttribute>() == null)
{
// Any service controller methods that are not implemented directly in the
// controller clreplaced or are not tagged by [ControllerValidation] are not
// considered for validation. This filters out base object methods
// like ToString(), GetType(),...
continue;
}
if (method.ReturnType == typeof(Microsoft.AspNetCore.Mvc.IActionResult))
{
errors.Error($"Controller method [{method.Name}(...)] returns [IActionResult] which is not supported. Use [ActionResult] or [ActionResult<T>] instead.");
}
var routeAttribute = method.GetCustomAttribute<Microsoft.AspNetCore.Mvc.RouteAttribute>();
string routeTemplate;
if (routeAttribute != null)
{
routeTemplate = routeAttribute.Template;
}
else
{
routeTemplate = method.Name;
}
var httpMethod = "GET";
var methodName = method.Name.ToUpperInvariant();
if (method.GetCustomAttribute<Microsoft.AspNetCore.Mvc.HttpDeleteAttribute>() != null)
{
httpMethod = "DELETE";
}
else if (method.GetCustomAttribute<Microsoft.AspNetCore.Mvc.HttpGetAttribute>() != null)
{
httpMethod = "GET";
}
else if (method.GetCustomAttribute<Microsoft.AspNetCore.Mvc.HttpHeadAttribute>() != null)
{
httpMethod = "HEAD";
}
else if (method.GetCustomAttribute<Microsoft.AspNetCore.Mvc.HttpOptionsAttribute>() != null)
{
httpMethod = "OPTIONS";
}
else if (method.GetCustomAttribute<Microsoft.AspNetCore.Mvc.HttpPatchAttribute>() != null)
{
httpMethod = "PATCH";
}
else if (method.GetCustomAttribute<Microsoft.AspNetCore.Mvc.HttpPostAttribute>() != null)
{
httpMethod = "POST";
}
else if (method.GetCustomAttribute<Microsoft.AspNetCore.Mvc.HttpPutAttribute>() != null)
{
httpMethod = "PUT";
}
else if (methodName.StartsWith("DELETE"))
{
httpMethod = "DELETE";
}
else if (methodName.StartsWith("GET"))
{
httpMethod = "GET";
}
else if (methodName.StartsWith("HEAD"))
{
httpMethod = "HEAD";
}
else if (methodName.StartsWith("OPTIONS"))
{
httpMethod = "OPTIONS";
}
else if (methodName.StartsWith("PATCH"))
{
httpMethod = "PATCH";
}
else if (methodName.StartsWith("POST"))
{
httpMethod = "POST";
}
else if (methodName.StartsWith("PUT"))
{
httpMethod = "PUT";
}
var signature = GetMethodSignature(method, httpMethod, routeTemplate, requireGeneratedParamAttribute: false);
if (controllerMethods.TryGetValue(signature, out var existing))
{
errors.Error($"[{controllerType.Name}] has multiple methods including\r\n\r\n {method.Name}(...)] and\r\n\r\n [{existing.Name}(...)]\r\n\r\n with the same parameters at endpoint [{httpMethod}:{routeTemplate}].");
}
else
{
controllerMethods.Add(signature, method);
}
}
// Load the client methods that call service endpoints.
foreach (var method in clientType.GetMethods(BindingFlags.Public | BindingFlags.Instance))
{
var generatedMethodAttribute = method.GetCustomAttribute<GeneratedMethodAttribute>();
if (generatedMethodAttribute == null)
{
continue;
}
var signature = GetMethodSignature(method, generatedMethodAttribute.HttpMethod, generatedMethodAttribute.RouteTemplate, requireGeneratedParamAttribute: true);
if (clientMethods.TryGetValue(signature, out var existing))
{
errors.Error($"[{clientType.Name}] has multiple methods including\r\n\r\n [{method.Name}(...)] and\r\n\t\n [{existing.Name}(...)]\r\n\r\n with the same parameters at endpoint [{generatedMethodAttribute.HttpMethod}:{generatedMethodAttribute.RouteTemplate}].");
}
else
{
clientMethods.Add(signature, method);
}
}
// Ensure that all of the client methods are also present in the controller.
foreach (var clientMethod in clientMethods)
{
if (!controllerMethods.ContainsKey(clientMethod.Key))
{
errors.Error($"Service controller [{controllerType.Name}] lacks a method that corresponds to:\r\n\r\n {clientType.Name}::{clientMethod.Value}\r\n\r\n with signature:\r\n\r\n {clientMethod.Key}]");
}
}
// Ensure that all of the controller methods are also present in the client.
foreach (var controllerMethod in controllerMethods)
{
if (!clientMethods.ContainsKey(controllerMethod.Key))
{
errors.Error($"Service client [{clientType.Name}] lacks a method that corresponds to:\r\n\r\n {controllerType.Name}::{controllerMethod.Value}\r\n\r\n with signature:\r\n\r\n {controllerMethod.Key}");
}
}
// Do a detailed comparision of the method return types and parameters.
foreach (var clientMethod in clientMethods)
{
if (controllerMethods.TryGetValue(clientMethod.Key, out var controllerMethod))
{
var clientParams = clientMethod.Value.GetParameters();
var controllerParams = controllerMethod.GetParameters();
// Note that we're using the controller parameter count rather than
// the client parameter count because the client methods were generated
// with extra (optional) parameters to specify timeout, retry policy, etc.
for (int i = 0; i < controllerParams.Length; i++)
{
var clientParam = clientParams[i];
var controllerParam = controllerParams[i];
var generatedClientParam = clientParam.GetCustomAttribute<GeneratedParamAttribute>();
if (generatedClientParam == null)
{
// Only the leading client method parameters that are actually preplaceded to the
// service have this attribute, so we can ignore parameters after these.
break;
}
// Ensure that parameter optionality is consistent.
if (clientParam.IsOptional != controllerParam.IsOptional)
{
if (controllerParam.IsOptional && !clientParam.IsOptional)
{
errors.Error($"[{clientType.Name}::{clientMethod}(...)] parameter [{clientParam.Name}] is optional which conflicts with the service definition which is not optional.");
}
else
{
errors.Error($"[{clientType.Name}::{clientMethod}(...)] parameter [{clientParam.Name}] is not optional which conflicts with the service definition which is optional.");
}
}
if (clientParam.IsOptional)
{
var defaultsAreEqual = true;
if ((clientParam.DefaultValue == null) != (controllerParam.DefaultValue == null))
{
defaultsAreEqual = false;
}
else if (clientParam.DefaultValue != null)
{
defaultsAreEqual = clientParam.DefaultValue.Equals(controllerParam.DefaultValue);
}
if (!defaultsAreEqual)
{
errors.Error($"[{clientType.Name}::{clientMethod}(...)] parameter [{clientParam.Name}] default value [{clientParam.DefaultValue}] does not match the controller default value [{controllerParam.DefaultValue}].");
}
}
// Ensure that the method for transmitting the parameter is consistent.
var fromQueryAttribute = controllerParam.GetCustomAttribute<Microsoft.AspNetCore.Mvc.FromQueryAttribute>();
if (fromQueryAttribute != null)
{
if (string.IsNullOrEmpty(fromQueryAttribute.Name))
{
fromQueryAttribute.Name = controllerParam.Name;
}
if (generatedClientParam.PreplacedAs != PreplacedAs.Query)
{
errors.Error($"[{clientType.Name}::{clientMethod}(...)] parameter [{clientParam.Name}] is preplaceded as [From{generatedClientParam.PreplacedAs}] which doesn't match the controller method parameter which requires [FromQuery].");
}
else if (generatedClientParam.Name != fromQueryAttribute.Name)
{
errors.Error($"[{clientType.Name}::{clientMethod}(...)] parameter [{clientParam.Name}] is preplaceded using name [{generatedClientParam.Name}] which doesn't match the controller method parameter which requires [{fromQueryAttribute.Name}].");
}
}
else
{
var fromRouteAttribute = controllerParam.GetCustomAttribute<Microsoft.AspNetCore.Mvc.FromRouteAttribute>();
if (fromRouteAttribute != null)
{
if (generatedClientParam.PreplacedAs != PreplacedAs.Route)
{
errors.Error($"[{clientType.Name}::{clientMethod}(...)] parameter [{clientParam.Name}] is preplaceded as [From{generatedClientParam.PreplacedAs}] which doesn't match the controller method parameter which requires [FromRoute].");
}
else if (generatedClientParam.Name != fromRouteAttribute.Name)
{
errors.Error($"[{clientType.Name}::{clientMethod}(...)] parameter [{clientParam.Name}] is preplaceded using route name [{generatedClientParam.Name}] which doesn't match the controller method parameter which requires [{fromRouteAttribute.Name}].");
}
}
else
{
var fromHeaderAttribute = controllerParam.GetCustomAttribute<Microsoft.AspNetCore.Mvc.FromHeaderAttribute>();
if (fromHeaderAttribute != null)
{
if (generatedClientParam.PreplacedAs != PreplacedAs.Header)
{
errors.Error($"[{clientType.Name}::{clientMethod}(...)] parameter [{clientParam.Name}] is preplaceded as [From{generatedClientParam.PreplacedAs}] which doesn't match the controller method parameter which requires [FromHeader].");
}
else if (generatedClientParam.Name != fromHeaderAttribute.Name)
{
errors.Error($"[{clientType.Name}::{clientMethod}(...)] parameter [{clientParam.Name}] is preplaceded using HTTP header [{generatedClientParam.Name}] which doesn't match the controller method parameter which requires [{fromHeaderAttribute.Name}].");
}
}
else
{
var fromBodyAttribute = controllerParam.GetCustomAttribute<Microsoft.AspNetCore.Mvc.FromBodyAttribute>();
if (fromBodyAttribute != null)
{
if (generatedClientParam.PreplacedAs != PreplacedAs.Body)
{
errors.Error($"[{clientType.Name}::{clientMethod}(...)] parameter [{clientParam.Name}] is preplaceded as [From{generatedClientParam.PreplacedAs}] which doesn't match the controller method parameter which requires [FromBody].");
}
}
else
{
// We default to [FromQuery] when nothing else is specified.
if (generatedClientParam.PreplacedAs != PreplacedAs.Query)
{
errors.Error($"[{clientType.Name}::{clientMethod}(...)] parameter [{clientParam.Name}] is preplaceded as [From{generatedClientParam.PreplacedAs}] which doesn't match the controller method parameter which implicitly specifies [FromQuery].");
}
else if (generatedClientParam.Name != controllerParam.Name)
{
errors.Error($"[{clientType.Name}::{clientMethod}(...)] parameter [{clientParam.Name}] is preplaceded using HTTP query parameter [{generatedClientParam.Name}] which doesn't match the controller method parameter which requires [{controllerParam.Name}].");
}
}
}
}
}
}
}
}
if (errors.HasErrors)
{
throw new IncompatibleServiceException("\r\n\r\n" + errors.ToString());
}
}