JsonProperty(Order = X)] is not working with [FromBody] and [FromRoute] - asp.net-core

In the serialized version, It returns Request as last object even though I have ordered it first. Is there a way to set Request order 1?
Is there anything like, FromBody will always be in the end?
public class Class1
{
[FromRoute(Name = "runId")]
[JsonProperty(Order = 2)]
public string Id { get; set; }
[FromBody]
[JsonProperty(Order = 1)]
public Request Request { get; set; }
}

Model Binding order of Class1 is decided by the order of properties in the model,not by [FromRoute] or[FromBody].So if you want to bind [FromBody] first,you can do like this.Here is a demo:
public class Class1
{
[FromBody]
public Sample Sample { get; set; }
[FromRoute(Name = "runId")]
public int Id { get; set; }
}
public class Sample
{
public int Foo { get; set; }
public string Name { get; set; }
}
Controller:
[HttpPost("Create/{runId}")]
public IActionResult Create(Class1 partner) {
return Ok();
}
result:

Related

Mapbox matching response convert to dynamic json in ASP.NET Core

I want to use mapbox matching in ASP.NET Core. This link you can get response https://api.mapbox.com/matching/v5/mapbox/driving/..
I want to convert this response to dynamic json in Asp.net core, I use this line
var jsonResponse = JsonConvert.DeserializeObject(mapResponse);
but I get empty values. Any help?
Firstly, The API you have shared I got follwing response using
postman:
If its same what you are getting then I follow below steps to retrive
the value from the API response in C# asp.net core controller
Model You should have :
public class Admin
{
public string iso_3166_1_alpha3 { get; set; }
public string iso_3166_1 { get; set; }
}
public class Leg
{
public List<object> via_waypoints { get; set; }
public List<Admin> admins { get; set; }
public double weight { get; set; }
public double duration { get; set; }
public List<object> steps { get; set; }
public double distance { get; set; }
public string summary { get; set; }
}
public class Matching
{
public double confidence { get; set; }
public string weight_name { get; set; }
public double weight { get; set; }
public double duration { get; set; }
public double distance { get; set; }
public List<Leg> legs { get; set; }
public string geometry { get; set; }
}
public class Tracepoint
{
public int matchings_index { get; set; }
public int waypoint_index { get; set; }
public int alternatives_count { get; set; }
public double distance { get; set; }
public string name { get; set; }
public List<double> location { get; set; }
}
public class MapResponseClass
{
public List<Matching> matchings { get; set; }
public List<Tracepoint> tracepoints { get; set; }
public string code { get; set; }
public string uuid { get; set; }
}
Asp.net core Controller:
public async Task<IActionResult> CallMapAPI()
{
try
{
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("https://api.mapbox.com/matching/v5/mapbox/driving/-117.17282,32.71204;-117.17288,32.71225;-117.17293,32.71244;-117.17292,32.71256;-117.17298,32.712603;-117.17314,32.71259;-117.17334,32.71254?access_token=pk.eyJ1Ijoibm92ZXJzbWFwIiwiYSI6ImNreTdwc3ppNTE3dzkyb3B2MnVzNXpueTUifQ.csYTL2GKkl99Yqk_TQjr5w");
response.EnsureSuccessStatusCode();
string mapAPIjson = await response.Content.ReadAsStringAsync();
var data = JsonConvert.DeserializeObject<MapResponseClass>(mapAPIjson);
}
catch (Exception ex)
{
throw;
}
return data;
}}
Output:
Note:
You should bound your class as per your API response. What I am
assuming of your empty values is you haven't converted the relevant
class accordingly. I hope above steps guided you accordingly.

Remove AspnetVersioning ApiVersion from Swagger Doc

Inside my route parameters I have need of the ApiVersion class, as shown below.
[HttpGet("v{version:apiVersion}/Company/{companyId}/absence/{id}")]
public async Task<IActionResult> Get([FromRoute]ApiVersion version, [FromRoute] int companyId, [FromRoute]int id)
{...
However including this makes swagger try to bind the ApiVersion model and requests, GroupVersion, MajorVersion, MinorVersion and Status. Is there a way for me to always remove these properties as they don't need to be provided.
You can add [BindNever] to your ApiVersion attributes:
ApiVersion class example:
public class ApiVersion
{
[BindNever]
public string GroupVersion { get; set; } = "aaa";
[BindNever]
public string MajorVersion { get; set; } = "bbb";
[BindNever]
public string MinorVersion { get; set; } = "ccc";
[BindNever]
public string Status { get; set; } = "ddd";
}
Result:

How to bind custom model class in mvc

I am new in MVC. I am working on a project where i have created a model class and also context class which is working good if i view the record in normal view.
but if i try to get the data in group by "Series_Name" and bind it into same model class it gives error. here is my code
Here is Model class and DBContextClass
[Table("tblvideo")]
public class TVSerial
{
[Key]
public Int64 Video_ID { get; set; }
public string Series_Name { get; set; }
public string Season_No { get; set; }
public string Episode_No { get; set; }
public string Episode_Name { get; set; }
public string Time_Duration { get; set; }
public string File_Url_480p { get; set; }
public string File_Url_720p { get; set; }
public string Description { get; set; }
public bool Is_Active { get; set; }
public string Image_Url_Small { get; set; }
public string Image_Url_Big { get; set; }
}
public class TvSerialContext : DbContext
{
public DbSet<TVSerial> TvSerials { get; set; }
}
Here is controller class:
public class TvSerialController : Controller
{
public ActionResult ListAllTvSerial()
{
try
{
TvSerialContext tvContext = new TvSerialContext();
List<TVSerial> tv = tvContext.TvSerials.ToList();
return View(tv);
}
catch (Exception ex)
{
return Content(ex.Message);
}
}
}
Above code works as expected, but if i am doing this :
public ActionResult ListAllSeason(string serial)
{
try
{
TvSerialContext tvContext = new TvSerialContext();
List<TVSerial> tv = tvContext.TvSerials.Where(tvs => tvs.Series_Name == serial).Distinct().ToList();
return View(tv);
}
catch (Exception ex)
{
return Content(ex.Message);
}
}
it return all rows , i just want single row from every series_name and custom field "Series_Name,Season_No,Image_Url_Big"
i don't know how to achieve this.
getting result :
Expected result:-
You could do this by creating a view model and using a .GroupBy() clause
public class TVSerialVM
{
public string SeriesName { get; set; }
public string SeasonNo { get; set; }
public string ImageUrl { get; set; }
}
and the query to project into your view model
List<TVSerialVM> model = tvContext.TvSerials.Where(t => t.Series_Name == serial)
.GroupBy(t => new { t.Series_Name, t.Season_No, t.Image_Url_Big })
.Select(t => new TVSerialVM
{
SeriesName = t.Key.Series_Name,
SeasonNo = t.Key.Season_No,
ImageUrl = t.Key.Image_Url_Big
}).ToList();
Side note: Your duplicating data in the database (the season number and the image url). You should consider moving the image urls to another table with a relationship to the season number.
The reason you are getting multiple values even though you are using distinct is the Distinct method does not know what "equal" is for TVSerial.
You can use Distinct with IEqualityComparer.
https://msdn.microsoft.com/en-us/library/vstudio/bb338049(v=vs.100).aspx
Distinct is not guaranteed to on custom objects it doesn't know what to compare. I have used this SO in the past to make my custom object work with Distinct.
Creating a distinct list of custom type in C#

Can't correctly add associated objects into Entity Framework Context

I have and entity framework project exposed via a data service:
public class VersionContext : DbContext
{
public DbSet<VersionTreeEntry> VersionTreeEntries { get; set; }
public DbSet<PluginState> PluginStates { get; set; }
public static void SetForUpdates()
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<VersionContext, Configuration>());
}
}
public class VersionTreeEntry
{
public VersionTreeEntry()
{
Children = new List<VersionTreeEntry>();
PluginStates = new List<PluginState>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
public virtual ICollection<VersionTreeEntry> Children { get; set; }
public virtual ICollection<PluginState> PluginStates { get; set; }
public virtual VersionTreeEntry Ancestor { get; set; }
/// <summary>
/// Links to the ProtoBufDataItem Id for the session state.
/// </summary>
public int DataId { get; set; }
public string Notes { get; set; }
[Required]
public DateTime TimeStamp { get; set; }
[MinLength(1, ErrorMessage = "Tag cannot have a zero length")]
[MaxLength(20, ErrorMessage = "A tag name cannot contain over 20 characters")]
public string Tag { get; set; }
public bool IsUiNodeExpanded { get; set; }
[Required]
public string Version { get; set; }
[Required]
public string SessionName { get; set; }
}
public class PluginState
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
public string PluginName { get; set; }
[Required]
public byte[] Data { get; set; }
}
As far as I can see, the data classes are defined correctly. I try to create some new objects and add them into the context, with their relations intact:
var session = new Session();
session.SessionName = "My new session";
VersionTreeEntry versionTreeEntry = new VersionTreeEntry();
versionTreeEntry.SessionName = session.SessionName;
versionTreeEntry.Version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
versionTreeEntry.TimeStamp = DateTime.Now;
_versionContext.AddToVersionTreeEntries(versionTreeEntry);
foreach (var plugin in session.Plugins)
{
using (var ms = new MemoryStream())
{
plugin.SaveState(ms);
PluginState state = new PluginState();
state.PluginName = plugin.PluginName;
state.Data = ms.ToArray();
versionTreeEntry.PluginStates.Add(state);
}
}
_versionContext.SaveChanges();
The problem is that the PluginState instances never actually get added to the database. If I add code to add them manually to the context, they do get added, but the foreign key pointing back to the VersionTreeEntry is null.
Again, this is a WCF DataService rather than vanilla EF, any idea what might be wrong?
Cheers
Posting the answer here from the comment section.
Agreed. The best way to do this is to call the following API:
_versionContext.AddRelatedObject(versionTreeEntry, "PluginStates", state);
Thanks
Pratik

EF5 Entry not updating

Im trying to update an entry with EF5 with the following actionresult:
[HttpPost]
public ActionResult Edit(int id, IEnumerable<HttpPostedFileBase> files)
{
if (ModelState.IsValid)
{
Reference reference = db.References.Single(x => x.Id == id);
db.Entry(reference).State = EntityState.Modified;
db.SaveChanges();
//Other stuff regarding files/images
return RedirectToAction("Index");
}
return View();
}
Nothing happens. When I debug it, it goes trough the code as everything was fine. But nothing is updated in the db.
Here's the model if needed:
public class Reference
{
public int Id { get; set; }
public string Headline { get; set; }
public string Text { get; set; }
public DateTime Date { get; set; }
public IEnumerable<HttpPostedFileBase> ImageUploadMain { get; set; }
public String MainFileName { get; set; }
public IEnumerable<HttpPostedFileBase> ImageUpload { get; set; }
public virtual ICollection<Image> Files { get; set; }
public virtual ICollection<RefProperties> Properties { get; set; }
public int CategoryId { get; set; }
public virtual Category Category { get; set; }
}
public class Image
{
public int Id { get; set; }
public string FileName { get; set; }
public virtual Reference Reference { get; set; }
}
public class RefProperties
{
public int Id { get; set; }
public string Key { get; set; }
public string Value { get; set; }
}
public class Category
{
public int CategoryId { get; set; }
public string Name { get; set; }
public virtual ICollection<Reference> References { get; set; }
}
Not only is the related entries not updated, a main property like "Headline" cant be updated either. What am I doing wrong? Create/delete works fine btw.
As Gert Arnold says, you're not actually modifying any of the Reference values so nothing will be updated. By calling db.Entry(reference).State = EntityState.Modified you're just setting the retrieved entity's state to modified in the ChangeTracker. When you call SaveChanges() it's just going to update the Reference record in the database with the same values that you fetched.
You need to update some of the Reference instance properties to see a change.
[HttpPost]
public ActionResult Edit(int id, IEnumerable<HttpPostedFileBase> files)
{
if (ModelState.IsValid)
{
Reference reference = db.References.Single(x => x.Id == id);
reference.HeaderText = "Changed";
/* No need to interact with the change tracker as the entity is already tracked and you've made a change */
// db.Entry(reference).State = EntityState.Modified;
/* Create/Modify/Update/Delete other entities */
db.SaveChanges();
//Other stuff regarding files/images
return RedirectToAction("Index");
}
return View();
}
Heres what I was looking for:
TryUpdateModel(reference, "");
It has a shitload of overloads. This works though