Requiring all parameters or return 404 - asp.net-mvc

I am trying to require the user to input all parameters into the URL like this:
http://127.0.0.1:5000/api/movies/1?foo=a&bar=c
The browser displays;
1 a c
I would like to ensure that all parameters are included in the URL, and the other combinations of parameters would result in 404. How do I modify the code to do this?
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using MoviesAPI.Services;
namespace MoviesAPI.Controllers
{
public interface IActionConstraint : IActionConstraintMetadata
{
/// <summary>
/// The constraint order.
/// </summary>
/// <remarks>
/// Constraints are grouped into stages by the value of <see cref="Order"/>. See remarks on
/// <see cref="IActionConstraint"/>.
/// </remarks>
/// <summary>
/// Determines whether an action is a valid candidate for selection.
/// </summary>
/// <param name="context">The <see cref="ActionConstraintContext"/>.</param>
/// <returns>True if the action is valid for selection, otherwise false.</returns>
bool Accept(ActionConstraintContext context);
}
public class RequiredFromQueryActionConstraint : IActionConstraint
{
private readonly string _parameter;
public RequiredFromQueryActionConstraint(string parameter)
{
_parameter = parameter;
}
public bool Accept(ActionConstraintContext context)
{
if (!context.RouteContext.HttpContext.Request.Query.ContainsKey(_parameter))
{
return false;
}
return true;
}
}
public class RequiredFromQueryAttribute : FromQueryAttribute, IParameterModelConvention
{
public void Apply(ParameterModel parameter)
{
if (parameter.Action.Selectors != null && parameter.Action.Selectors.Any())
{
parameter.Action.Selectors.Last().ActionConstraints.Add(new RequiredFromQueryActionConstraint(parameter.BindingInfo?.BinderModelName ?? parameter.ParameterName));
}
}
}
[Route("api/[controller]")]
public class MoviesController : Controller
{
private MoviesDbContext _context;
public MoviesController(MoviesDbContext context)
{
_context = context;
}
public IActionResult GetMovies()
{
return Ok(_context.Movies);
}
[HttpGet("{id}")]
public string Get(int id, [RequiredFromQuery]string foo, [RequiredFromQuery]string bar)
{
return id + " " + foo + " " + bar;
}
}
}

IActionConstraint Interface is included in Microsoft.AspNetCore.Mvc.ActionConstraints.
Remove your interface code and add the Order property for the RequiredFromQueryActionConstraint
public class RequiredFromQueryActionConstraint : IActionConstraint
{
private readonly string _parameter;
public RequiredFromQueryActionConstraint(string parameter)
{
_parameter = parameter;
}
public int Order => 999;
public bool Accept(ActionConstraintContext context)
{
if (!context.RouteContext.HttpContext.Request.Query.ContainsKey(_parameter))
{
return false;
}
return true;
}
}
public class RequiredFromQueryAttribute : FromQueryAttribute, IParameterModelConvention
{
public void Apply(ParameterModel parameter)
{
if (parameter.Action.Selectors != null && parameter.Action.Selectors.Any())
{
parameter.Action.Selectors.Last().ActionConstraints.Add(new RequiredFromQueryActionConstraint(parameter.BindingInfo?.BinderModelName ?? parameter.ParameterName));
}
}
}
Refer to https://www.strathweb.com/2016/09/required-query-string-parameters-in-asp-net-core-mvc/

Related

How to make a common class for common code in a controller

I have two controllers both are derivated from a base controller. The code inside them is exactly the same. The only difference is in constructors. Below is my code:
[RoutePrefix("api/v2")]
public class CategoryController : BaseController
{
private IGetTroubleTicketService getTroubleTicketService;
private ICategoryService categoryService;
/// <summary>
/// Constructor for initialization
/// </summary>
public CategoryController()
{
getTroubleTicketService = MethodFactory.Create<IGetTroubleTicketService>();
getTroubleTicketService.SetProvider(new ServiceProvider(Global.Container));
categoryService = MethodFactory.Create<ICategoryService>();
categoryService.SetProvider(new ServiceProvider(Global.Container));
}
/// <summary>
/// Retrieve all Categories
/// </summary>
/// <returns>Categories(Id, Label)</returns>
[HttpGet]
[Route("categoryRef")]
public HttpResponseMessage Categories()
{
try
{
// Validate User Id and Application Id
var user = ValidateUserAndApplication(getTroubleTicketService);
var userLanaguage = Convert.ToInt32(user.Language, CultureInfo.InvariantCulture);
var categories = categoryService.CategoriesData(userLanaguage);
LoggingRequest("categoryRef",null);
response = Request.CreateResponse(HttpStatusCode.OK, categories);
}
catch (Exception exception)
{
//CheckError
CheckError(exception);
}
return response;
}
}
The second one is
[RoutePrefix("api/v2")]
public class ProblemCategoryController : BaseController
{
private IGetTroubleTicketService getTroubleTicketService;
private ICategoryService categoryService;
/// <summary>
/// Constructor for initialization
/// </summary>
public ProblemCategoryController()
{
getTroubleTicketService = MethodFactory.Create<IGetTroubleTicketService>();
getTroubleTicketService.SetProvider(new ServiceProvider(Global.Container));
categoryService = MethodFactory.Create<ICategoryService>();
categoryService.SetProvider(new ServiceProvider(Global.Container));
}
/// <summary>
/// Retrieve all Natures of problem
/// </summary>
/// <returns>Categories(Id, Label)</returns>
[HttpGet]
[Route("problemCategoryRef")]
public HttpResponseMessage ProblemCategories()
{
try
{
// Validate User Id and Application Id
var user = ValidateUserAndApplication(getTroubleTicketService);
var userLanaguage = Convert.ToInt32(user.Language, CultureInfo.InvariantCulture);
var categories = categoryService.CategoriesData(userLanaguage);
LoggingRequest("problemCategoryRef", null);
response = Request.CreateResponse(HttpStatusCode.OK, categories);
}
catch (Exception exception)
{
//CheckError
CheckError(exception);
}
return response;
}
Now as you can see the internal code is exactly the same which I want to avoid creating a Helper class. How can I make this common class for it so as to remove code duplicacy? It's possible without rewrite all the context code to get User and Id app?
I tried this
public class NatureOfProblemHelper : BaseController
{
private IGetTroubleTicketService getTroubleTicketService;
private ICategoryService categoryService;
private string resourceName;
/// <summary>
/// Initializes a new instance of the <see cref="NatureOfProblemHelper"/> class.
/// Constructor for initialization.
/// <param name="resource">Resource requested by user.</param>
/// </summary>
public NatureOfProblemHelper(string resource)
{
getTroubleTicketService = MethodFactory.Create<IGetTroubleTicketService>();
getTroubleTicketService.SetProvider(new ServiceProvider(Global.Container));
categoryService = MethodFactory.Create<ICategoryService>();
categoryService.SetProvider(new ServiceProvider(Global.Container));
resourceName = resource;
}
/// <summary>
/// Retrieve all Natures of problem.
/// </summary>
/// <returns>Categories(Id, Label).</returns>
public HttpResponseMessage GetNaturesOfProblem()
{
// Validate User Id and Application Id
var user = ValidateUserAndApplication(getTroubleTicketService);
var userLanaguage = Convert.ToInt32(user.Language, CultureInfo.InvariantCulture);
var categories = categoryService.CategoriesData(userLanaguage);
LoggingRequest(resourceName, null);
return Request.CreateResponse(HttpStatusCode.OK, categories);
}
And then into each controller
[HttpGet]
[Route("problemCategoryRef")]
public HttpResponseMessage ProblemCategories()
{
try
{
response = natureOfProblem.NaturesOfProblem();
}
catch (Exception exception)
{
//CheckError
CheckError(exception);
}
return response;
}
This build, but I can't get the context that comes from this variable
// Validate User Id and Application Id
var user = ValidateUserAndApplication(getTroubleTicketService);
Why if I put the same lines of code directly in my controller works but if I put in my Helper it doesn't work??

How to configure Ninject in call scope binding within Azure Web Job?

I am facing a problem when try to write a web job scheduler. I am using Ninject scope binding using EF Repository pattern. But Only InSingletonScope() work as expected. How to configure it in RequestScope Or Call Scope ?
//Register Context
Kernel.Bind<MyDbContext>().ToSelf().InSingletonScope();
Kernel.Bind<IUnitOfWork<MyDbContext>>().To<UnitOfWork<MyDbContext>>().InSingletonScope();
Problem Solved From One of My Previous Post
I am posting Step By Step Solution
(1.) NinjectJobActivator
public class NinjectJobActivator : IJobActivator
{
#region Variable Declaration
private readonly IResolutionRoot _resolutionRoot;
#endregion
#region CONSTRUCTOR
/// <summary>
///
/// </summary>
/// <param name="kernel"></param>
// public NinjectJobActivator(IKernel kernel)
public NinjectJobActivator(IResolutionRoot resolutionRoot)
{
_resolutionRoot = resolutionRoot;
}
#endregion
#region CreateInstance
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T CreateInstance<T>()
{
return _resolutionRoot.Get<T>(new CallScopedParameter());
}
#endregion
}
(2) NinjectBindings
using Ninject.Extensions.Conventions;
using Ninject.Extensions.NamedScope;
public class NinjectBindings : NinjectModule
{
public override void Load()
{
//Register Context
Kernel.Bind<MyDbContext>().ToSelf()
.When(x => x.Parameters.OfType<CallScopedParameter>().Any())
.InCallScope(); // For Scheduler
Kernel.Bind<IUnitOfWork<MyDbContext>>().To<UnitOfWork<MyDbContext>>();
//Register Repository
Kernel.Bind(x => x
.FromAssemblyContaining<MyDbContext>()
.SelectAllClasses()
.InheritedFrom(typeof(IRepository<>))
.BindDefaultInterface());
}
}
(3) Program.cs
static void Main()
{
using (IKernel kernel = new StandardKernel(new NinjectBindings()))
{
var config = new JobHostConfiguration()
{
JobActivator = new NinjectJobActivator(kernel)
};
if (config.IsDevelopment)
{
config.UseDevelopmentSettings();
}
// Timer Trigger
config.UseTimers();
var host = new JobHost(config);
//// The following code ensures that the WebJob will be running continuously
host.RunAndBlock();
}
}
(4) CallScopedParameter
public sealed class CallScopedParameter : IParameter
{
/// <summary>
///
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
public bool Equals(IParameter other)
{
if (other == null)
{
return false;
}
return other is CallScopedParameter;
}
/// <summary>
///
/// </summary>
/// <param name="context"></param>
/// <param name="target"></param>
/// <returns></returns>
public object GetValue(IContext context, ITarget target)
{
throw new NotSupportedException("this parameter does not provide a value");
}
/// <summary>
///
/// </summary>
public string Name
{
get { return typeof(CallScopedParameter).Name; }
}
/// <summary>
/// this is very important
/// </summary>
public bool ShouldInherit
{
get { return true; }
}
}
(5) Azure Web Job Function
public void DoSomething([TimerTrigger("*/30 * * * * *")] TimerInfo timer, TextWriter log)
{
try
{
var tempdetails = _sampleRepository.SearchFor(x=> DateTime.UtcNow > x.DateTo);
foreach (var detail in tempdetails)
{
if (detail.ID == 2)
{
detail.ID = 5;
}
_sampleRepository.Update(detail);
}
_unitOfWork.Commit();
}
catch (Exception ex)
{
log.WriteLine(ex.Message);
}
}

NSubstitute: Mocking the request, response object inside a MVC/Web Api Controller?

I am trying to find how to mock both the Request and Response objects that are available inside a controller from MVC / Web Api.
Is this possible, I am not injecting the Request and Response objects, these are available because the controllers inherit from ApiController or Controller.
Does anyone have some good examples for getting access to these through nsubstitute ?
Also what about the other objects like context ?
You do not have to mock them.
Since they have read/write properties, all you have to do is to create them. I explain it a bit more in our book and we have a class that allows you to do this:
var orderController = ControllerContextSetup
.Of(() => new OrderController(mockOrderService.Object))
.WithDefaultConfig()
.WithDefaultRoute()
.Requesting(url)
.WithRouteData(new {controller="Order"})
.Build<OrderController>();
I am sharing the code here so it can be used:
public class ControllerContextSetup
{
private const string DefaultApiName = "DefaultApi";
private readonly ApiController _controller;
private HttpRouteData _httpRouteData;
private ControllerContextSetup(ApiController controller)
{
_controller = controller;
_controller.Request = new HttpRequestMessage();
}
public static ControllerContextSetup Of<T>(Func<T> factory)
where T : ApiController
{
return new ControllerContextSetup(factory());
}
public static ControllerContextSetup Of<T>()
where T : ApiController, new()
{
return new ControllerContextSetup(new T());
}
public ControllerContextSetup WithDefaultConfig()
{
_controller.Configuration = new HttpConfiguration();
_controller.Request.Properties[HttpPropertyKeys.HttpConfigurationKey] = _controller.Configuration;
return this;
}
public ControllerContextSetup WithConfig(HttpConfiguration configuration)
{
_controller.Request.Properties[HttpPropertyKeys.HttpConfigurationKey] = configuration;
_controller.Configuration = configuration;
return this;
}
public ControllerContextSetup Requesting(string uriString)
{
Uri uri = null;
bool success = Uri.TryCreate(uriString, UriKind.Relative, out uri);
if (success)
return Requesting(uri);
success = Uri.TryCreate(uriString, UriKind.Absolute, out uri);
if(success)
return Requesting(uri);
return Requesting(new Uri(uriString));
}
public ControllerContextSetup Requesting(Uri uri)
{
_controller.Request.RequestUri = uri;
return this;
}
public ControllerContextSetup WithDefaultRoute()
{
_controller.Configuration.Routes.MapHttpRoute(
name: DefaultApiName,
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
return this;
}
public ControllerContextSetup WithRoute(string name, string routeTemplate)
{
_controller.Configuration.Routes.MapHttpRoute(name, routeTemplate);
return this;
}
public ControllerContextSetup WithRoute(string name, string routeTemplate, object defaults)
{
_controller.Configuration.Routes.MapHttpRoute(name, routeTemplate, defaults);
return this;
}
public ControllerContextSetup WithRoute(string name, string routeTemplate, object defaults, object constraints)
{
_controller.Configuration.Routes.MapHttpRoute(name, routeTemplate, defaults, constraints);
return this;
}
public ControllerContextSetup WithRoute(string name, IHttpRoute route)
{
_controller.Configuration.Routes.Add(name, route);
return this;
}
/// <summary>
/// Uses default route
/// </summary>
/// <param name="routeValues"></param>
/// <returns></returns>
public ControllerContextSetup WithRouteData(object routeValues)
{
return WithRouteData(new HttpRouteValueDictionary(routeValues));
}
/// <summary>
/// Uses default route
/// </summary>
/// <param name="routeValues"></param>
/// <returns></returns>
public ControllerContextSetup WithRouteData(HttpRouteValueDictionary routeValues)
{
var route = _controller.Configuration.Routes[DefaultApiName];
_httpRouteData = new HttpRouteData(route, routeValues);
_controller.Request.Properties[HttpPropertyKeys.HttpRouteDataKey] = _httpRouteData;
return this;
}
public ControllerContextSetup WithMethod(HttpMethod method)
{
_controller.Request.Method = method;
return this;
}
public ApiController Build()
{
_controller.ControllerContext =
new HttpControllerContext(_controller.Configuration,
_httpRouteData ?? new HttpRouteData(_controller.Configuration.Routes.FirstOrDefault()) ,
_controller.Request);
return _controller;
}
public T Build<T>()
where T : ApiController
{
return (T) Build();
}
}

How can I redirect from my controller using AuthorizeAttributes?

I have made an AuthorizeAttributeBase to extend AuthorizeAttribute.
It looks like this:
public abstract class MyAuthorizeAttribute : AuthorizeAttribute
{
//Holds the roles allowed to perform the action.
public IEnumerable<string> roles { get; set; }
/// <summary>
/// Authorizes if the current user may perform the action
/// </summary>
/// <param name="httpContext">Unused - included for override purposes.</param>
/// <returns>true if authorized.</returns>
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//Return true if user is in the action allowed roles.
if (IsUserInRole)
{
return true;
}
else
{
HttpContext.Current.Response.StatusCode = 401;
return false;
}
}
/// <summary>
/// Checks if the user is member of a role that is allowed by the authorization
/// </summary>
public bool IsUserInRole
{
get
{
if (roles != null)
{
//Check if any of the roles in the session is in the list of roles of the authorization
return (MySessionGetter.GetSession().Roles.Intersect<string>(roles).Any());
}
//If none of the roles match return false.
return false;
}
}
/// <summary>
/// Sets the allowed roles of the authorization
/// </summary>
/// <param name="userRoles">Allowed roles</param>
public void AlowedRoles(IEnumerable<string> userRoles)
{
roles = userRoles;
}
I keep the allowed rolenames like this:
/// <summary>
/// Holds the role names.
/// </summary>
public static class UserRoles
{
public static string Administrators = "Administrators";
public static string Teachers= "Teachers";
}
And use my base like this:
/// <summary>
/// Authorization for the access to the SomeAction
/// </summary>
public class AuthorizeAccessToSomeActionAttribute : MyAuthorizeAttribute
{
public AuthorizeAccessToSomeActionAttribute()
{
AlowedRoles(new List<string> { UserRoles.Adminstrators,
UserRoles.Teachers });
}
}
And last but not least the controller:
/// <summary>
/// The main Index view of application
/// </summary>
/// <returns>Application Index views</returns>
[AuthorizeAccessToSomeAction]
public ActionResult Index()
{
return View("Index");
}
Now what I want to do is make the index switch return value on base of the AuthorizeAttributes.
Lets say Teachers to the TeachersIndex() and Administrators to the AdministratorsIndex().
I tried adding this to the base:
//Checks if the current user is authorized.
public bool IsAuthorized()
{
return AuthorizeCore(new HttpContextWrapper());
}
But I end up having to create new AutorizeAttributes every time.
Making it static seemed to give me even more problems.
Is there a correct way of going about this?
Solved it. :)
The OnAuthorization override got me a new lead.
Found this question.
I put the redirects in a Dictionary<string, RedirectToRouteResult> because I like the idea of keeping all role strings in one place instead of filling up my controllers with magic strings.
public static Dictionary<string, RedirectToRouteResult> HomeRedirect
{
get
{
return new Dictionary<string, RedirectToRouteResult> {
{"Administrators", new RedirectToRouteResult(
new RouteValueDictionary { { "action", "AdministratorIndex" }, { "controller", "MyController" }})},
{"Teacher", new RedirectToRouteResult(
new RouteValueDictionary { { "action", "TeacherIndex" }, { "controller", "MyController" }})}
};
And the override HandleUnauthorizedRequest looks like this now:
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) {
filterContext.Result = UserRoles.HomeRedirect
.SingleOrDefault(m => m.Key == MySessionGetter.GetSession().Roles.First()).Value;
}
Take a look at RedirectToRouteResult and RedirectResult.
Here would be a good start:
// Redirects users of given role to given action
public class AuthorizeAccessToSomeActionAttribute : MyAuthorizeAttribute
{
public string Role { get; set; }
public string RedirectToAction { get; set; }
public AuthorizeAccessToSomeActionAttribute(string role, string action)
{
Role = role;
RedirectToAction = action;
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
// Test if current user is in the role
if (filterContext.HttpContext.User.IsInRole(Role))
{
// Get current routevalues
var rvals = filterContext.RouteData.Values;
// Change action
rvals["action"] = RedirectToAction;
filterContext.Result = new RedirectToRouteResult("Default",rvals);
}
}
}
Usage:
// Redirect role to given action
[AuthorizeAccessToSomeActionAttribute("Teacher", "TeacherIndex" )]
[AuthorizeAccessToSomeActionAttribute("Admin", "AdminIndex" )]
public ActionResult Index()
...
public ActionResult TeacherIndex()
...
public ActionResult AdminIndex()

Web api HTTP 500 (Internal Server Error)

Hello I have an error 500 (internal server error) when I run the code below. My issue is that I have no trace at all of the error. It seems that visual studio is unable to catch it.
The following code returns a Candidate if I try to add pers to candidate the code fail and i get error 500. The thing is PersonAddressDescription implement AddressDescription is inheritance the problem ?
public class CheckController : ApiController
{
public Candidate Get()
{
PersonAddressDescription pers = new PersonAddressDescription();
Candidate candidate = new Candidate();
//IF I REMOVE THIS NO PROBLEM
candidate.address = pers;
return candidate;
}
}
AddressDescription class
/// <remarks/>
[System.Xml.Serialization.XmlIncludeAttribute(typeof(CompanyAddressDescription))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(PersonAddressDescription))]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.17626")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.crif-online.ch/webservices/crifsoapservice/v1.00")]
public abstract partial class AddressDescription : object, System.ComponentModel.INotifyPropertyChanged {
private Location locationField;
private ContactItem[] contactItemsField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=0)]
public Location location {
get {
return this.locationField;
}
set {
this.locationField = value;
this.RaisePropertyChanged("location");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("contactItems", Order=1)]
public ContactItem[] contactItems {
get {
return this.contactItemsField;
}
set {
this.contactItemsField = value;
this.RaisePropertyChanged("contactItems");
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName) {
System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if ((propertyChanged != null)) {
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}
PersonAddressDescription class that implement AddressDescription
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.17626")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.crif-online.ch/webservices/crifsoapservice/v1.00")]
public partial class PersonAddressDescription : AddressDescription {
private string firstNameField;
private string lastNameField;
private string maidenNameField;
private Sex sexField;
private bool sexFieldSpecified;
private string birthDateField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=0)]
public string firstName {
get {
return this.firstNameField;
}
set {
this.firstNameField = value;
this.RaisePropertyChanged("firstName");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=1)]
public string lastName {
get {
return this.lastNameField;
}
set {
this.lastNameField = value;
this.RaisePropertyChanged("lastName");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=2)]
public string maidenName {
get {
return this.maidenNameField;
}
set {
this.maidenNameField = value;
this.RaisePropertyChanged("maidenName");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=3)]
public Sex sex {
get {
return this.sexField;
}
set {
this.sexField = value;
this.RaisePropertyChanged("sex");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool sexSpecified {
get {
return this.sexFieldSpecified;
}
set {
this.sexFieldSpecified = value;
this.RaisePropertyChanged("sexSpecified");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=4)]
public string birthDate {
get {
return this.birthDateField;
}
set {
this.birthDateField = value;
this.RaisePropertyChanged("birthDate");
}
}
}
I suspect that the object you retrieved (addResp) contains circular references somewhere in its object graph. Circular references cannot be JSON serialized.
For example try putting the following code inside your controller to test what happens when you attempt to JSON serialize this instance:
TypeIdentifyAddressResponse addResp = ws.identifyAddress("test");
string json = JsonConvert.SerializeObject(addResp);
UPDATE:
It seems that AddressDescription is an abstract class and your actual instance is PersonAddressDescription. You need to indicate that to the serializer by using the [KnownType] attribute:
[KnownType(typeof(PersonAddressDescription))]
[KnownType(typeof(CompanyAddressDescription))]
...
public abstract partial class AddressDescription : object, System.ComponentModel.INotifyPropertyChanged {
{
...
}
As an alternative if you don't want to further pollute your (already polluted) domain models with other attributes you could also define the known type inside your WebApiConfig.cs:
config.Formatters.XmlFormatter.SetSerializer<Candidate>(
new DataContractSerializer(typeof(Candidate),
new Type[] { typeof(PersonAddressDescription) }));

Resources