1

I have a Web Api project sharing its models with internal customers, such as this:

public PaymentController : ApiController
{
    public IHttpAction PostPayment(PaymentRequest request)
    {
    }
}

[Validator(typeof(PaymentRequestValidator))]
public class PaymentRequest
{
}

Where we're using FluentValidation to validate incoming requests:

public class PaymentRequestValidator : AbstractValidator<PaymentRequest>
{
}

When a client makes a call:

httpClient.PostAsJsonAsync("api/payment", new PaymentRequest());

Json.Net reads and tries to instantiate custom attributes on the type. Since we don't ship FluentValidation alongside with the models it causes an exception:

Could not load file or assembly 'FluentValidation, Version=6.0.2.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.

Stack trace:

at System.ModuleHandle.ResolveType(RuntimeModule module, Int32 typeToken, IntPtr* typeInstArgs, Int32 typeInstCount, IntPtr* methodInstArgs, Int32 methodInstCount, ObjectHandleOnStack type)
at System.ModuleHandle.ResolveTypeHandleInternal(RuntimeModule module, Int32 typeToken, RuntimeTypeHandle[] typeInstantiationContext, RuntimeTypeHandle[] methodInstantiationContext)
at System.Reflection.RuntimeModule.ResolveType(Int32 metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
at System.Reflection.CustomAttribute.FilterCustomAttributeRecord(CustomAttributeRecord caRecord, MetadataImport scope, Assembly& lastAptcaOkAssembly, RuntimeModule decoratedModule, MetadataToken decoratedToken, RuntimeType attributeFilterType, Boolean mustBeInheritable, Object[] attributes, IList derivedAttributes, RuntimeType& attributeType, IRuntimeMethodInfo& ctor, Boolean& ctorHasParameters, Boolean& isVarArg)
at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeModule decoratedModule, Int32 decoratedMetadataToken, Int32 pcaCount, RuntimeType attributeFilterType, Boolean mustBeInheritable, IList derivedAttributes, Boolean isDecoratedTargetSecurityTransparent)
at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeType type, RuntimeType caType, Boolean inherit)
at Newtonsoft.Json.Utilities.ReflectionUtils.GetAttributes(Object attributeProvider, Type attributeType, Boolean inherit)
at Newtonsoft.Json.Serialization.JsonTypeReflector.GetAssociateMetadataTypeFromAttribute(Type type)
at Newtonsoft.Json.Utilities.ThreadSafeStore`2.AddValue(TKey key)
at Newtonsoft.Json.Utilities.ThreadSafeStore`2.Get(TKey key)
at Newtonsoft.Json.Serialization.JsonTypeReflector.GetAttribute[T](Type type)
at Newtonsoft.Json.Utilities.ThreadSafeStore`2.AddValue(TKey key)
at Newtonsoft.Json.Utilities.ThreadSafeStore`2.Get(TKey key)
at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateContract(Type objectType)
at Newtonsoft.Json.Serialization.DefaultContractResolver.ResolveContract(Type type)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.WriteStartArray(JsonWriter writer, Object values, JsonArrayContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)
at System.Net.Http.Formatting.JsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)
at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)

Is it possible to avoid that? In other way than ship them together.

2
  • Possibly a custom contract resolver? Commented Mar 12, 2016 at 7:29
  • @zaitsman: will try next week, thanks Commented Mar 12, 2016 at 17:02

1 Answer 1

1

Create two different copies of the PaymentRequest class implementing the same interface, in separate namespaces. Maybe something like this:

public interface IPaymentRequest 
{
}

//This class will be shipped to your clients. 
public class PaymentRequestDTO: IPaymentRequest
{
} 


//This class will be used in your WebAPI or Server Side code.
[Validator(typeof(PaymentRequestValidator))]
public class PaymentRequest: IPaymentRequest
{
} 

Then you only need to ship the DTO class for all your clients, but use your internal implementation with your validator on un server side.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.