I am in creation of webapi odata service. I have a post method named "Validate" in my controller named "User" as below:
public class UserController : ODataController
{
[HttpPost]
public HttpResponseMessage Post(LoginEntityDto objLogin)
{
//mylogin
}
}
//Custom class
public class LoginEntityDto
{
public string username { get; set; }
public string password { get; set; }
}
I am inputting this post method with the below JSON Format
{
"username": "C201566",
"password" : "pwd"
}
I am using the content-type : application / json
but in my post method the input objLogin is always null
Please help me in resolving this issue.
OData/Webapi doesn't support post a complex type in this way, why not make it as an entity type by define the key and entityset.
[key]
username {get;set;}
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<LoginEntityDto>("LoginEntityDto");
or you can use action to post this complex type as parameter.
FYI: http://odata.github.io/WebApi/#04-07-action-parameter-support
Related
Route Config
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
POST-method
[HttpPost]
public Probabilities Post(string word, string userId) {
Request request = new Request();
request.Identify(word, userId);
Probabilities probabilities = probabilitiesFactory.GetBy(request.ProbabilitiesId, "Id");
return probabilities;
}
Im trying to post some data, shown on the screenshot
And im getting an error
"No action was found on the controller 'Identification' that matches the request."
What is happening? How to post 2 simple strings and get the result
While not mandatory, you should follow good practice and encapsulate the payload into a model.
public class MyModel {
public sting word { get; set; }
public sting userId { get; set; }
}
You can then use the FromBody parameter attribute to bind the model to the data sent.
Finally addressing the resource not found issue, ensure that the controller is following the proper convention given that the OP is configured with convention-based routing.
public class IdentificationController : ApiController {
[HttpPost]
public Probabilities Post([FromBody] MyModel model) {
string word = model.word;
string userId = model.userId;
Request request = new Request();
request.Identify(word, userId);
Probabilities probabilities = probabilitiesFactory.GetBy(request.ProbabilitiesId, "Id");
return probabilities;
}
}
Reference: Parameter Binding in ASP.NET Web API
Reference: Routing in ASP.NET Web API
There are 2 different solutions for this problem.
First:
Send word and userId as QueryStrings.. here's an example:
http://localhost/api/identification?word=hey&&userId=12
this will work in your case so you won't need to change anything in the code.
And Finally my favorite solution:
Create a model class like that:
public class IdentificationModel{
public string word { get; set; }
public string userId { get; set; }
}
then require it as a parameter object in you method like that:
[HttpPost]
public Probabilities Post(IdentificationModel requestModel) {
Request request = new Request();
request.Identify(requestModel.word, requestModel.userId);
Probabilities probabilities = probabilitiesFactory.GetBy(request.ProbabilitiesId, "Id");
return probabilities;
}
The last one does not require adding [FromBody] attribute since any class object is an api method will automatically be waited as a Request Body Object.
C# Web.Api Odata APplication
I’m implementing Odata V4 for the first time and would like to use my own custom class instead of the data class from the designer.
Here is what I did:
I created a Data project in Visual Studios and added my SQL Linq data table “Video”
I created the data context as follows:
public class VideoDataContext : DbContext
{
public VideoDataContext(): base("name=VideoData")
{
DbSet<VideoEf> Videos { get; set; }
}
And my custom class as follows:
[Serializable]
[DataContract]
public class VideoEf : Repository
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Isrc { get; set; }
}
And model builder:
public Microsoft.OData.Edm.IEdmModel GetEdmModel()
{
ODataModelBuilder builder = new ODataConventionModelBuilder();
EntityTypeConfiguration<VideoEf> titleType = builder.EntityType<VideoEf>();
builder.EntitySet<VideoEf>("Video");
return builder.GetEdmModel();
}
And in my video controller:
public class VideoController : ODataController
{
VideoDataContext db = new VideoDataContext ();
[EnableQuery(PageSize = 20, MaxExpansionDepth = 5)]
public IHttpActionResult Get()
{
return Ok(db.Videos.AsQueryable());
}
When I make the call to get the video entities I keep getting a ” 406 Not Acceptable” error message
How can I ensure that the data returned from the database is mapped to my custom model ?
Is my model builder correct?
what could be causing the above error?
You don't need to return IQueryable because you have EnableQuery attribute, just return DbSet.
You also don't need any wcf attribute and EntityTypeConfiguration<VideoEf> titleType = builder.EntityType<VideoEf>();
Then it should just work.
Hope it helps.
Edit
My mistake for IQueryable, I also use it.
So I'm trying to add a "like" function to some blog posts by POSTing some JSON through ajax to the MVC api controller.
Models:
public class Blog{
public int ID{get;set;}
public string Title{get;set;}
//Some more stuff
public virtual ICollection<Likes> Likes {get;set;}
}
public class Likes{
public int ID{get;set;}
public string UserName{get;set;}
//Some more stuff
public virtual Blog Blog{get;set;}
}
Controller:
public void Post(Likes like){
if(ModelState.IsValid){
db.Likes.Add(like)
db.SaveChanges();
}
}
The below return is passed into the JSON.stringify() in the ajax call:
var UserName = "Dave";
//More stuff
var Blog = "????";
return {UserName:UserName, More Stuff, Blog:Blog}
So that last line is my problem I think, what do I pass in for "Blog"? I have tried using the ID of the Blog but it's still null in the controller. It seems the controller wants a full Blog model instead of just the ID, is there a way around this or am I doing something bad?
TLDR I guess is: What to pass to a field that's a public virtual Blog Blog{get;set;} in the model when sending JSON to the controller?
P.S. My code works when I don't include the "Blog" as part of the JSON.
if you are posting a like then this would probably do the thing
{
ID : 789 //ID of the Like
UserName : "Username",
Blog : {
ID : 789 //id of the blog
}
}
This way you will have the id of the blog and would be mapped correctly.
But i would advise you make a separate view model of the following structure
public LikeAjax
{
public string UserName{get; set;}
public int BlogId {get; set;}
}
then send json like below
{
UserName : "User Name",
BlogId : 789
}
I want to test a MVC action method which accpets a custom class parameter via POST (e.g. Book), I have problem passing the parameter via fiddler. Below is my code:
[HttpPost]
public ActionResult BookEdit(BookModel bookModel)
{
...
return View(...);
}
public class BookModel
{
public BookModel()
{
}
public BookModel(Book book)
{
this.Authors = book.Authors;
}
public List<Author> Authors { get; set; }
}
public class Book
{
public List<Author> Authors = new List<Author>();
}
public class Author
{
public string Name { get; set; }
}
Below is the xml that is post to the action method
<BookModel>
<Authors>
<Author>
<Name>1</Name>
</Author>
<Author>
<Name>2</Name>
</Author>
</Authors>
</BookModel>
When I pass the xml, the parameter to the action method is null.
Any idea?
When I pass the xml, the parameter to the action method is null.
Well, that's normal. I can't see any code of yours which would parse this XML into a BookModel object. ASP.NET MVC doesn't do this by default. It does it for JSON, but not XML.
One possibility would be to write a custom Xml value provider as shown here. Another possibility is a custom action filter attribute. Yet another one is a custom model binder.
I have implemented a custom membership provider and have the following class;
public class ProfileCommon : ProfileBase
{
#region Members
[Required(ErrorMessage="Required")]
public virtual string Title
{
get { return ((string)(this.GetPropertyValue("Title"))); }
set { this.SetPropertyValue("Title", value); }
}
I then, in my controller want to do the following;
[HttpPost]
[Authorize]
public ActionResult EditInvestorRegistration(FormCollection collection)
{
ProfileCommon profileCommon= new ProfileCommon();
TryUpdateModel(profileCommon);
This kinda fails when title is not included with the error;
Property accessor 'Title' on object 'Models.ProfileCommon' threw the following exception:'The settings property 'Title' was not found.'
If I get rid of the attribute [Required... it works fine but now I no longer have automatic validation on my object.
Now, I know I could check each property at a time and get around the issue but I'd dearly like to use DataAnnotations to do the work for me.
Any ideas?
It seems strange that you are using a custom profile class as action input instead of a view model:
public class ProfileViewModel
{
[Required]
public string Title { get; set; }
}
and then in your controller you could use AutoMapper to convert between the view model and the model class which will update the profile:
[HttpPost]
[Authorize]
public ActionResult EditInvestorRegistration(ProfileViewModel profileViewModel)
{
ProfileCommon profileCommon = AutoMapper.Map<ProfileViewModel, ProfileCommon>(profileViewModel);
...
}