I have a simple ASP.NET Class with 4 properties. What I'd like to to is package this class into a JSON string and add a "data" parent at the top level. What's the best way to add in the "data" element at the top level?
using Newtonsoft.Json;
[DataContract]
public class Task
{
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "notes")]
public string Notes { get; set; }
}
static void Main(string[] args)
{
var task = new Task();
task.Name = "Test Task";
task.Notes = "Test task created by ASP.NET";
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("https://example.com/api");
HttpResponseMessage response = client.PostAsJsonAsync<Task>("tasks", task).Result;
response.EnsureSuccessStatusCode();
string responseBody = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(responseBody);
Console.ReadLine();
}
The Json I am getting back from this code is the following:
{
"name": "Test Task",
"notes": "Test task created by ASP.NET",
}
What I'd like is the following:
{
"data": {
{
"name": "Test Task",
"notes": "Test task created by ASP.NET",
}
}
You could create a simple dictionary:
public class Task
{
public Task
{
Data = new Dictionary<string,string>();
}
[DataMember(Name = "data")]
public Dictionary<string,string> Data { get; private set; }
}
Populate like:
Task t =new Task();
t.Data.Add("name","test task");
t.Data.Add("notes","teet");
Yes you could create another class and embed it like this also:
public class Data
{
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "notes")]
public string Notes { get; set; }
}
public class Task
{
public Task
{
Data = new Data();
}
[DataMember(Name = "data")]
public Data Data { get; private set; }
}
You could use generics for an abstracted Data
public class Task<T> where T: class , new()
{
public Task
{
Data = new T();
}
[DataMember(Name = "data")]
public T Data { get; private set; }
}
If your service provider is wcf (i guess it is wcf), change the BodyStyle of the method to WebMessageBodyStyle.Bare as mentioned below.
BodyStyle = WebMessageBodyStyle.Bare
it will not wrap the result.
Related
I have a simple RESTful API and this is the post route handler I'm trying to apply AutoMapper in:
[HttpPost]
[Route("[action]")]
public async Task<IActionResult> CreateHotel([FromBody]Hotel hotelCreateDto)
{
var hotel = _mapper.Map<Hotel>(hotelCreateDto);
var createdHotel = await _hotelService.CreateHotel(hotel);
var hotelReadDto = _mapper.Map<HotelReadDto>(createdHotel);
return CreatedAtAction("GetHotelById", new { id = hotelReadDto.Id }, hotelReadDto);
}
So in the request I get a hotelCreateDto which looks like that:
public class HotelCreateDto
{
[StringLength(50)]
[Required]
public string Name { get; set; }
[StringLength(50)]
[Required]
public string City { get; set; }
}
and I map this to Hotel entity:
public class Hotel
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[StringLength(50)]
[Required]
public string Name { get; set; }
[StringLength(50)]
[Required]
public string City { get; set; }
}
and a new hotel object is created in the next line. However when hotelReadDto is going to be assigned to the new mapped object, a 500 error occurs: "AutoMapper.AutoMapperMappingException: Missing type map configuration or unsupported mapping."
Could you catch a mistake here? I don't know where I'm doing wrong.
Edit: there'S also this things after the error above: "Mapping types:
Object -> HotelReadDto
System.Object -> HotelFinder.DTO.DTOs.HotelReadDto"
Edit2: Here is the code in the Configure Services:
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
And in the Profile class:
public class HotelProfile : Profile
{
public HotelProfile()
{
CreateMap<Hotel, HotelReadDto>();
CreateMap<HotelCreateDto, Hotel>();
}
}
Add this in your services in startup :
it's reusable and cleaner
public void ConfigureServices(IServiceCollection services)
{
services.AddAutoMapper(Assembly.GetExecutingAssembly());
}
add these interface and class in your project
public interface IMapFrom<T>
{
void Mapping(Profile profile) => profile.CreateMap(typeof(T), GetType());
}
using AutoMapper;
using System;
using System.Linq;
using System.Reflection;
public class MappingProfile : Profile
{
public MappingProfile()
{
ApplyMappingsFromAssembly(Assembly.GetExecutingAssembly());
}
private void ApplyMappingsFromAssembly(Assembly assembly)
{
var types = assembly.GetExportedTypes()
.Where(t => t.GetInterfaces()
.Any(i =>i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMapFrom<>)))
.ToList();
foreach (var type in types)
{
var instance = Activator.CreateInstance(type);
var methodInfo = type.GetMethod("Mapping")
?? type.GetInterface("IMapFrom`1").GetMethod("Mapping");
methodInfo?.Invoke(instance, new object[] { this });
}
}
}
and your dto be like this (map hotel to HotelDto):
public class HotelCreateDto : IMapFrom<HotelCreateDto>
{
[StringLength(50)]
[Required]
public string Name { get; set; }
[StringLength(50)]
[Required]
public string City { get; set; }
public void Mapping(Profile profile)
{
profile.CreateMap<Hotel,HotelCreateDto>();
}
}
public class Paypal//name of class
public string Pay { get; set; }//Field called pay
public Paypal() { }//General constructor
public class Amount//into Paypal class
{
[JsonProperty(PropertyName = "currency_code")]
public string CurrencyCode { get; set; }
[JsonProperty(PropertyName = "value")]
public string Value { get; set; }
}
now is a method into Paypal class:
public static string ConvertToPay()
{
var request = new OrdersRequest
{
Intent = "CAPTURE",
PurchaseUnits = new PurchaseUnit[]{ new PurchaseUnit{
Amount = new Amount//New object from above
{
CurrencyCode = "USD",
Value ="???"//Here I want to get a different amount every time
}
}
}
};
var jsonContent = JsonConvert.SerializeObject(request);
return jsonContent;
}
in page some.cs written
Paypal.Amount payamo = new Paypal.Amount();
payamo.Value= SumOfClass.Items[SumOfClass.SelectedIndex].Value;
It does not work! How the Value will get a variable amount??
I tried several ways, with no success
I have a web api class in my web api project which has an object parameter and an output parameter
public class ProductsController : ApiController
{
[HttpGet]
public List<Product> GetProducts(out QueryResult queryResult, GlobalInfo globalInfo)
{
var repository = new BusinessRepository();
return repository.GetAllProducts(out queryResult,globalInfo);
}
}
QueryResult and GlobalInfo class is :
class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public decimal Price { get; set; }
}
public class QueryResult
{
private QueryStatus _queryStatus;
public QueryStatus QueryStatus
{
get { return _queryStatus; }
set { _queryStatus = value; }
}
private string _errorCode;
public string ErrorCode
{
get { return _errorCode; }
set { _errorCode = value; }
}
private string _errorText;
public string ErrorText
{
get { return _errorText; }
set { _errorText = value; }
}
}
public enum QueryStatus
{
None,
Error,
RecordFound,
RecordNotFound,
AccessDenied,
Succeded
}
public class GlobalInfo
{
public string UserName { get; set; }
public int UserId { get; set; }
public string IP { get; set; }
}
how to call web api method in console app or asp.net mvc by oject parameter and out object parameter?
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
QueryResult result;
var globalinfo = new GlobalInfo{UserName = "user1",UserId = 12,IP = "98.14.0.1"};
var data = new JavaScriptSerializer().Serialize(globalinfo);
var methodUrl = string.Format("http://localhost/WebApi/api/products/?queryResult={0}&globalInfo={1}",result,data);
var response = client.GetAsync(methodUrl).Result;
response.EnsureSuccessStatusCode();
var content = response.Content.ReadAsAsync<List<Product>>().Result;
I am creating a REST service using Web API and am using EF Code First to retrieve and store data to back end that service. I have a bunch of classes defined and the EF creates the database no problems at all. I can retrieve the data and again have no issues. The problem I experience is when I try to write back a record. If I have created the following little mock up to reproduce the problem.
public class Company
{
[Key]
public int CompanyID { get; set; }
public string Name { get; set; }
}
public class Contact
{
[Key]
public int ContactID { get; set; }
public int CompanyID { get; set; }
public virtual Company Company { get; set; }
public string Name { get; set; }
}
public class Quote
{
[Key]
public int QuoteID { get; set; }
public int CustomerID { get; set; }
[ForeignKey("CustomerID")]
public virtual Company Customer { get; set; }
public int ContactID { get; set; }
public virtual Contact Contact { get; set; }
public string Reference { get; set; }
}
I then have three controllers in my REST service;
public class CompaniesController : ApiController
{
TestDBContext Context = new TestDBContext();
public IEnumerable<Company> GetCompanies()
{
return Context.Companies;
}
}
[Route("api/companies/{CompanyID}/contacts")]
public class CompanyContactsController : ApiController
{
TestDBContext Context = new TestDBContext();
public IEnumerable<Contact> GetCompanyContacts(int CompanyID)
{
return Context.Contacts.Where(C => C.CompanyID == CompanyID);
}
}
public class QuotesController : ApiController
{
TestDBContext Context = new TestDBContext();
public HttpResponseMessage PostQuote(Quote value)
{
try
{
if (ModelState.IsValid)
{
Context.Quotes.Add(value);
Context.SaveChanges();
// Return the object in the body.
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, value);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = value.QuoteID }));
return response;
}
}
catch
{
}
return new HttpResponseMessage(HttpStatusCode.InternalServerError);
}
}
I pre-populate the database with a company and a contact and then have the following code to create a quote.
HttpClient Client = new HttpClient();
string CompanyURL = "http://localhost:56619/api/Companies";
string ContactURL = "http://localhost:56619/api/Companies/{0}/Contacts";
string QuoteURL = "http://localhost:56619/api/Quotes";
Client.GetAsync(CompanyURL).ContinueWith((T) =>
{
T.Result.EnsureSuccessStatusCode();
T.Result.Content.ReadAsAsync<IEnumerable<Company>>().ContinueWith((T2) =>
{
Company Comp = T2.Result.First();
Client.GetAsync(string.Format(ContactURL, Comp.CompanyID)).ContinueWith((T3) =>
{
T3.Result.EnsureSuccessStatusCode();
T3.Result.Content.ReadAsAsync<IEnumerable<Contact>>().ContinueWith((T4) =>
{
Contact Cont = T4.Result.First();
Quote Q = new Quote() { Customer = Comp, Contact = Cont, Reference = "Test" };
JsonMediaTypeFormatter Formatter = new JsonMediaTypeFormatter();
Formatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
Client.PostAsync<Quote>(QuoteURL, Q, Formatter).ContinueWith((T5) =>
{
T5.Result.EnsureSuccessStatusCode();
T5.Result.Content.ReadAsAsync<Quote>().ContinueWith((T6) =>
{
var Res = T6.Result;
});
});
});
});
});
});
I know the code is a little scrappy, but it is just thrown together to illustrate the problem without any extra stuff cluttering the code up.
When the EF saves the changes to the database it creates 1 quote, an extra contact and 2 extra company records. I'm puzzled as to why. I am using VS2013, EF6 and Web API 2.
If anyone has any suggestions they would be very gratefully be received.
Many thanks in advance,
Neil.
I am new in ASP.NET world and I am trying to achieve following.
I need to serialize API of this format
{
"results": {
"profile": {
"firstname": "John,
"lastname": "Newman",
},
"credit": {
"amount": 30
}
}
}
The problem is that I don't know how to model my data. I need a results object, which contains 2 other objects (profile and credit). You can see some sample code below.
public class Results
{
public class Data {
public Profile profile { get; set; }
public Credit credit {get; set; }
}
public class Profile {
public String firstname {get; set; }
public String lastname { get; set; }
}
public class Credit {
public int amount { get; set; }
}
}
static void Main(string[] args)
{
Results results= new Results
{
Data = new Data{
Profile = new Profile {
firstname = "John",
lastname = "Newman"
},
Credit = new Credit {
balance = "30"
}
}
};
string json = JsonConvert.SerializeObject(results);
Console.WriteLine(json);
}
The error I get is "Member Data cannot be initialized. It is not a field or property. What am I doing wrong?
Try this instead:
public class Profile
{
public String firstname { get; set; }
public String lastname { get; set; }
}
public class Credit
{
public int amount { get; set; }
}
public class Result
{
public Profile profile { get; set; }
public Credit credit { get; set; }
}
public class Wrapper
{
public Result results { get; set; }
}
static void Main(string[] args)
{
var wrapper = new Wrapper
{
results = new Result
{
profile = new Profile
{
firstname = "John",
lastname = "Newman"
},
credit = new Credit
{
amount = 30
}
}
};
string json = JsonConvert.SerializeObject(wrapper);
Console.WriteLine(json);
}
Try this :
static void Main(string[]args) {
Base results = new Base() {
Results = new Results() {
profile = new Profile() {
firstname = "John",
lastname = "Newman"
},
credit = new Credit() {
amount = 30
}
}
};
string json = JsonConvert.SerializeObject(results);
Console.WriteLine(json);
Console.ReadLine();
}
public class Base {
public Results Results {get;set;}
}
public class Results{
public Profile profile {get;set;}
public Credit credit {get;set;}
}
public class Profile{
public String firstname {get;set;}
public String lastname {get;set;}
}
public class Credit{
public int amount {get;set;}
}
Class Base wraps Results class to get the required JSON structure.