The Delta for Patch is null - asp.net-web-api

Here are my Entities. I am using entity framework code first.
public class Trade
{
public Guid Id { get; set; }
[MaxLength(10)]
public string AssetClass { get; set; }
public TradeBatch Batch { get; set; }
}
public class TradeBatch
{
public TradeBatch()
{
StartedOn = DateTime.Now;
}
public Guid Id { get; set; }
public DateTime StartedOn { get; set; }
public List<Trade> Trades { get; set; }
}
In My Controller I have:
[AcceptVerbs("PATCH")]
public void UpdateTrade(Guid id, Delta<Trade> update)
{
var tradeToUpdate = _repTradeService.GetRepTradeById(id);
update.Patch(tradeToUpdate);
_repTradeService.SaveChanges();
}
When I Make a request (using fiddler), update is null.
Here is the patch Request:
PATCH http://localhost:61579/api/RepTrades/4e43b48a-a4fd-4ffc-841d-08dac55deb60 HTTP/1.0
User-Agent: Fiddler
Host: localhost:61579
Content-Length: 55
Content-Type: application/json
{"AssetClass":"Test"}
The value for "Update" in the Patch Action is always null. Any pointers to why?

You may want to try setting the content-type header to application/json;odata=verbose
I would have just commented but don't have the reputation yet.

Your JSON is fine, and the method should accept it as far as I can see. You can see what the exact error is by adding the following line of code at the top of your PATCH method:
if (!ModelState.IsValid) {
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState));
}
This way, if your JSON is not valid according to the model the method is expecting, it returns a HTTP 400 Bad Request message, along with the ModelState. The message of that response will contain the reason why the ModelState is not valid.

In my case the answer from #kazu helped me find the problem because it gave me a break point where the debugger could reveal the problem.
I had a setter in my class, which was trying to set a property on an object which had not been initialised. By breaking with the debugger on the "throw" command, I was able to see the stack trace in the properties of the ModelState object, and the stacktrace said my setter on a particular field was throwing "Object Reference Not Set". With that I could immediately see the problem.
My object was like this:
public MyObject
{
private PrivateObjectType _privateObject;
public MyObject()
{
}
public string myProperty
{
get { return _privateObject.myProperty; }
set { _privateObject.myProperty = value; }
}
}
So obviously I needed to put this in the constructor:
_privateObject = new PrivateObjectType();

Related

ASP.NET Web API - how to pass unknown number of form-encoded POST values

The front-end of my application can send unknown number of POST values inside a form. Fro example in some cases there will be 3 values coming from certain textboxes, in some cases there will be 6 values coming from textboxes, dropdowns etc. The backend is ASP.NET Web API. I know that a simple .NET value can be passed in URI parameter to a "POST Action" using FromURI attribute and a complex type can be passed in body and fetched using FromBody attribute, in any POST Action. But in my case the number of form data values will NOT be constant rather variable and I can't use a pre-defined class to hold values using 'FromBody' attribute.
How can I tackle this situation?
You can use the FormDataCollection from the System.Net.Http.Formatting namespace.
public class ApiFormsController : ApiController
{
[HttpPost]
public IHttpActionResult PostForm(FormDataCollection form)
{
NameValueCollection items = form.ReadAsNameValueCollection();
foreach (string key in items.AllKeys)
{
string name = key;
string val = items[key];
}
return Ok();
}
}
Try to send this properties as list of properties. Make model something like this:
public class PostModel
{
public IEnumerable<PropertyModel> Properties { get; set; }
}
public class PropertyModel
{
public string Value { get; set; }
public string Source { get; set; }
// etc.
}
And action:
public IHttpActionResult Post(PostModel model)
{
//Omited
return Ok();
}

Using Automapper to map object to realm object with Xamarin and c#

I am creating an Xamarin.iOS app and a Realm database.I would like to keep my POCO objects separate from my RealmObject so what I did was use a repository pattern and within the repository I tried to use AutoMapper to map the POCO to the RealmObject
e.g. (subset)
public class PlaceRepository : IPlaceRepository
{
private Realm _realm;
public PlaceRepository(RealmConfiguration config)
{
_realm = Realm.GetInstance(config);
}
public void Add(Place place)
{
using (var trans = _realm.BeginWrite())
{
var placeRealm = _realm.CreateObject<PlaceRealm>();
placeRealm = Mapper.Map<Place, PlaceRealm>(place);
trans.Commit();
}
}
So, if I debug my code everything maps OK and placeRealm is populated OK but when I commit nothing gets saved to the Realm db. The following is my RealmObject
public class PlaceRealm : RealmObject
{
[ObjectId]
public string Guid { get; set; }
public string Title { get; set; }
public string Notes { get; set; }
}
and this is my POCO Place
public class Place
{
public string Guid { get; set; }
public string Title { get; set; }
public string Notes { get; set; }
}
And AutoMapper is initialized like so:
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Place, PlaceRealm>();
cfg.CreateMap<PlaceRealm, Place>();
});
All standard stuff. Has anyone else managed to get something similar working?
Your poco 'Place' is called 'PlaceRealm'. I suspect that is a typo. (made edit)
I suspect that Automapper is instantiating a new object overwriting your original 'placeRealm' object.
Perhaps you could try
Mapper.Map(place, placeRealm);
in place of your current mapping.
which should just copy the values to your already instatiated and tracked object.
(no need to store the return value).
You might also want to make explicit which properties (3) you are mapping as currently Automapper will map all including those in the base class.
On a side note, you may run into performance issues with Automapper. I found it to be the performance bottleneck in some apps. ExpressMapper is a nice alternative.

Service returning string only has added quotes when coming from the cache

I built a simple Hello service that uses the cache. DTO:
[DataContract]
[Route("/cachedhello/{Name}")]
public class CachedHello : IReturn<string>
{
[DataMember]
public string Name { get; set; }
public string CacheKey
{ get { return "urn:cachedhello:nm=" + Name; } }
}
Here is the service:
public class CachedHelloService : Service
{
public ICacheClient CacheClient { get; set; }
public object Any(CachedHello request)
{
return base.Request.ToOptimizedResultUsingCache(
this.CacheClient, request.CacheKey, CacheExpiryTime.DailyLoad(), () =>
{
return "(Cached) Hello, " + request.Name;
});
}
}
When I use the JSONServiceClient to call this service, the returned string has quotes around it. when I look at the cache entries in my database, it does look like an extra set of quotes have been put around the .json version of the entry:
urn:cachedhello:nm=Matt (Cached) Hello, Matt
urn:cachedhello:nm=Matt.json """(Cached) Hello, Matt"""
urn:cachedhello:nm=Matt.json.deflate U9JwTkzOSE3RVPBIzcnJ11HwTSwpUQIA
Here's the code that calls the service from VB.NET
Dim s = _ServiceClient.Send(Of String)(New CachedHello() With {.Name = "Matt"})
We've removed double-encoding of raw string responses in this commit. This issue should now resolved in the latest v4.0.33+ of ServiceStack that's now available on MyGet.

Visual Studio WCF Client creates classes with missing properties, adds ExtensionData property instead

I have a WCFService that returns sundry types of Data in this kind of a way:
[DataContract( Name="Amazing", NameSpace="http://schemas.myorganisation.com/DataContract1")]
Public class AmazingDto
{
[DataMember( Order=0, IsRequired=true )]
public string Name { get; set; }
[DataMember( Order=0, IsRequired=true )]
public bool IsAmazing { get; set; }
}
And then
[DataContract ( Name="GetAmazingListResponse", NameSpace="http://schemas.myorganisation.com/DataContract1")]
Public class GetAmazingListResponseDto
{
[DataMember(Order=0, IsRequired-true, EmitDefaultValue=False)]
public ICollection<AmazingDto> AmazingList{ get; set; }
}
Also
[DataContract(Name = "Response", Namespace = "http://schemas.myorganisation.com/DataContract1")]
public class ResponseDto<TData> : BaseResponseDto
{
public ResponseDto();
[DataMember(Order = 0, IsRequired = true)]
public StatusDto Status { get; set; }
[DataMember(Order = 1, IsRequired = false, EmitDefaultValue = false)]
public TData Data { get; set; }
}
And then
public ResponseDto<GetAmazingListResponseDto> GetAmazingList()
{
var response = new ResponseDto<GetAmazingListDto>
{
Status = new StatusDto { StatusResult = StatusResultEnum.Success },
Data = new GetAmazingListResponseDto
{
AmazingList = new List<AmazingDto>
{
new AmazingDto { Name="Ponies", IsAmazing=true },
new AmazingDto { Name="Glenatron", IsAmazing=false }
}
}
};
return response;
}
Now when I make a call to that service using a tool like SoapUI I get exactly the response I might expect.
<GetAmazingListResult xmlns:a="http://schemas.myorganisation.com/DataContract1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Status>
<a:StatusResult>Success</a:StatusResult>
</a:Status>
<a:Data xmlns:b="http://schemas.myorganisation.com/DataContract1">
<b:AmazingList>
<b:Amazing>
<b:Name>Ponies</b:Name>
<b:IsAmazing>true</b:IsAmazing>
</b:Amazing>
<b:Amazing>
<b:Name>Glenatron</b:Name>
<b:IsAmazing>false</b:IsAmazing>
</b:Amazing>
</b:AmazingList>
</a:Data>
</GetAmazingListResult>
However, when I use Visual Studio 2010 to create a Service Reference and make a call like this:
var client= new FindoutAmazingnessServiceClient();
var response = client.GetAmazingList();
What I find is that response only has two properties, Status and ExtensionData. I have seen this described in other SE questions but the answer was always that something was missing a DataContract or DataMember on the data contracts. I definitely have those, so something else must be happening so that VS.Net can't see my classes. I have tried referencing the DTO library that contains these files and trying to configure the reference to match types with that library, but it makes no difference.
Where am I going wrong?
Just Add [DataMember] to your data members. It solved my problem.
The solution I have found is, as I am working against my own WCF service, to import the interfaces into my client and then use ChannelFactory to set up the connection. This works very well in my scenario, but doesn't solve the problem I am raising with this question.

webapi action overload

here are my actions
public AddressModel[] Get()
{
return addresses.ToArray();
}
public AddressModel Get([FromUri]GetAddressModelById model)
{
return Addresses.FirstOrDefault(x => x.Id == model.Id);
}
...
public class GetAddressModelById
{
public Guid Id { get; set; }
}
the urls looks like this
domain:port/api/controller
domain:port/api/controller/[guid]
and the routing is the default routing.
When I run this i get the exception Multiple actions were found that match the request. what am I missing for this to work?
Try domain:port/api/controller/model=[guid]
It would also be good if you could do:
public AddressModel Get([FromUri]Guid model)
{
...
}
The reason you're getting this error is because if you request for domain:port/api/controller, we cannot decide whether to dispatch it to Get() or Get([FromUri]GetAddressModelById model) with model set to null. You have following two options in this case
Use plain Guid type parameter instead of the class wrapper
Post your complex type in body instead of sending it through URI

Resources