How to include/exclude properties from a WEB API response based on a user's role using attributes? For example:
public class Employee
{
public string FullName { get; set;}
[DataMember(Role="SystemAdmin")] // included only for SystemAdmins
public string SSN { get; set; }
}
You can use conditional serialization depending on what serializer(s) you are using in web api.
If you are just returning JSON from Web API its simple - I use only the JSON serializer and this solution works for me. By default Web API uses JSON.Net for JSON serialization. You can add a ShouldSerialize method that returns a bool. In the should serialize you can test if the user IsInRole
public class Employee
{
public string Name { get; set; }
public string Manager { get; set; }
public bool ShouldSerializeManager()
{
// don't serialize the Manager property for anyone other than Bob..
return (Name == "Bob");
}
}
More details
The [JsonIgnore] attribute is all or nothing when using the JSON.Net Web API serialization.
Other serializers require different approaches...
The XmlSerializer also supports this but you have to enable it
config.Formatters.XmlFormatter.UseXmlSerializer = true;
The datacontract serializer is the default.
If using this you would have to add logic into the properties and omit them if null.. This can be a problem if you use the class elsewhere. The [IgnoreDataMember] attribute is all or nothing.
[DataContract]
public class Person
{
private string firstName;
[DataMember(IsRequired = false, EmitDefaultValue = false)]
public string FirstName
{
get
{
//Put here any condition for serializing
return string.IsNullOrWhiteSpace(firstName) ? null : firstName;
}
set
{
firstName = value;
}
}
}
Related
Hi I am trying to build an endpoint for slack commands in asp.net core 2.2.
I have a data structure representing a commandrequest from slack like so:
public class SlackCommandDTO
{
[FromForm(Name = "token")]
public string Token { get; set; }
[FromForm(Name = "team_id")]
public string TeamId { get; set; }
[FromForm(Name = "team_domain")]
public string TeamDomain { get; set; }
[FromForm(Name = "channel_id")]
public string ChannelId { get; set; }
[FromForm(Name = "channel_name")]
public string ChannelName { get; set; }
[FromForm(Name = "user_id")]
public string UserId { get; set; }
[FromForm(Name = "user_name")]
public string UserName { get; set; }
[FromForm(Name = "command")]
public string Command { get; set; }
[FromForm(Name = "text")]
public string Text { get; set; }
[FromForm(Name = "response_url")]
public string ResponseUrl { get; set; }
[FromForm(Name = "trigger_id")]
public string TriggerId { get; set; }
}
My controller to receive data looks like this:
[Route("api/[controller]")]
[ApiController]
public class CustomerServiceController : ControllerBase
{
// POST api/customerservice
[HttpPost]
public void Post([FromForm] SlackCommandDTO command)
{
Console.Write(command.Token);
}
}
my startup.cs looks like this
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}
I have tried setting the compatability settings in startup.cs to 2.1 and 2.2.
The result is always an instance of the object that contain null in all properties.
I have tried setting the decorator to [FromBody] (not that that is supposed to work) but in that case I get 415 unsupported media type (as it should).
I have tried sending the requests with content-type x-www-form-urlencoded and form-data as well as text/plain and application/json. the latter two return 415.
I have also tried sending the request through swagger with the same result and curl both using -d keyword and -F keyword for each pair of data.
If I am missing some information please let me know, I am drawing a blank here on how to solve it so please help.
The data I am receiving is from Slack according to this article about implementing slash commands in slack.
https://api.slack.com/slash-commands#responding_to_commands
I have solved my problem.
My issue was the fundamental misunderstanding that the parameters would be bound as a single object when using the FromForm attribute when actually I was supposed to parameterize each field as a string input in the post method like so:
[Route("api/[controller]")]
[ApiController]
public class CustomerServiceController : ControllerBase
{
// POST api/customerservice
[HttpPost]
public void Post([FromForm] string token,
[FromForm] string team_id,
[FromForm] string team_domain,
[FromForm] string channel_id,
[FromForm] string channel_name,
[FromForm] string user_id,
[FromForm] string user_name,
[FromForm] string command,
[FromForm] string text,
[FromForm] string response_url,
[FromForm] string trigger_id)
{
Console.Write(token);
}
}
[FromForm] is not for annotating properties on your model. It's for indicating how an action param will be bound. If you were accepting JSON, you could achieve this via [JsonProperty], but there's no way to change the property names for binding from form. They need to match, i.e. you'll either need to change your properties to stuff like Team_Id (with the underscore) or change your field names to stuff like teamId (without the underscore).
I'm trying to exclude a property from my Post Action in a web api controller, is there something like [Bind(Exclude="Property")] for asp.net web api?
This is my model:
public class ItemModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
I want to exclude the Id in the Post Action, because it is autogenerated, but I need to return it in my Get Action.
I Know I could have two models, one for my Post action and one for my Get action, but I'm trying to do this with just one model.
I would favour mapping models but this could be achieved by checking if the request is a POST in a ShouldSerialize method:
public class MyModel
{
public string MyProperty1 { get; set; }
public string MyProperty2 { get; set; }
public bool ShouldSerializeMyProperty2()
{
var request = HttpContext.Current.Request;
if (request.RequestType == "POST") return false;
return true;
}
}
Where your method name is the name of the property prefixed with ShouldSerialize.
Note this will work for JSON. For XML, you will need to add the following line to your config:
config.Formatters.XmlFormatter.UseXmlSerializer = true;
You can simply create a DTO for POST.
I need to return a collection with nested optional collections from my WebAPI and convert it back to objects in my Web UI, however I'm getting the following error:
Cannot create and populate list type System.Linq.IQueryable`1[MyNamespace.MyClass].
I'm using Json.Net.
Here is a sample of my code:
public class ClassA
{
public Int64 Id { get; set; }
public String Description { get; set; }
public IEnumerable<ClassB> { get; set; }
}
public class ClassB
{
public Int64 Id { get; set; }
public String Description { get; set; }
}
I've saw some questions here in stackoverflow, but I don't have access to serialization options (it is handled internally by our library).
UPDATE
I've forgot to mention that ClassA is returned as an IQueryable in my Web API.
Changing the return type of my Web API method to IEnumerable instead of IQueryable solved the problem.
In c#, Need example for web api post with multiple parameter ,Below i have attached my sample code.Please look into the InsertLeave method.In my code without CompanyId parameters working fine. When i add the companyid not able to invoke.
namespace AeS.SaaSAPI_2116
{
[RoutePrefix("{CompanyId}/{SecurityKey}")]
public class LeaveController : ApiController
{
[HttpPost]
[Route("{APIName}/x")]
public string InsertLeave(List<LeaveRequest> objList, string CompanyId)
{
foreach (LeaveRequest LR in objList)
{
}
return "Sucess ";
}
}
}
public class LeaveRequest
{
[Required]
public string EMP_STAFFID { get; set; }
[Required]
public string LEAVE_TYPE { get; set; }
}
}
I think you can use send your parameter to the server by request body, You will have to create a single class that wrapping your all parameters.You can use model binding to resolve this kind of issue
I am using MongoDB database with MVC4 WebAPI using the C# driver provided by MongoDB. I have a an issue with serialization. I get the following error,
"ExceptionMessage=Error getting value from '__emptyInstance' on 'MongoDB.Bson.ObjectId'"
If I change the Content-Type to xml in my HTTP request it just works fine. I would appreciate any help.
I have copied the model below.
public class Subscriber
{
public ObjectId _id;
public long SubscriberId { get; set; }
public Name Name { get; set; }
public Address Address { get; set; }
public string Phone { get; set; }
public ICollection<Subscription> Subscription { get; set; }
public Subscriber()
{
Name = new Name();
Address = new Address();
Subscription = new Collection<Subscription>();
}
}
Solution
Converting _id type string and decorating the field as below did the trick
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string _id;
reference: JSON.NET cast error when serializing Mongo ObjectId
For anyone trying the mentioned "solution" in the answer : It simply doesn't work!
Check the marked answer in this, instead.