Niteesh Kumar
Niteesh Kumar

Reputation: 213

how to modify response in .net mvc web api

Hi i have a C# model class. This class i need to pass as json response by setting his property . one property name Product of this class have type of another product class, when there is no data for Product i am getting all inner property value as blank but instead of that i want blank json property .

For Exp My Class is

 public class Profile_BO
{

    public int Id { get; set; }
    public string Username { get; set; }
    public Product product{ get; set; }


    public class Product
    {
        public int Id { get; set; }
        public string Type { get; set; }
    }
}

i am initializing this class from C# data table like below : -

       Profile_BO profile_BO = new Profile_BO();

            foreach (DataRow dr in result.Tables[0].Rows)
            {
                profile_BO.Id = Convert.ToInt32(dr[0]);
                profile_BO.Username = Convert.ToString(dr[1]);
            }

            Product product = new Product();

            foreach (DataRow dr1 in result.Tables[1].Rows)
            {
                product.Id = Convert.ToInt32(dr1[0]);
                product.Type = Convert.ToString(dr1[1]);
            }

            profile_BO.product = product;

Finally when i am passing as a response to method : -

 public async Task<HttpResponseMessage> GetUserInfo(Profile_Request profile_Request)
    {
           return request.CreateResponse(HttpStatusCode.OK, profile_BO);
}

And when calling on client side i am getting response json if data is present in table like : -

{
  "Id": "1",
  "Username": "abc",
  "product": {
    "Id": "232",
    "Type": "34cvdcbv"
  }
}

But when i have no data in product table i am getting below : -

{
  "Id": "1",
  "Username": "abc",
  "product": {
    "Id": 0,
    "Type": ""
  }
}

But if no data i want output like below : -

{
  "Id": "1",
  "Username": "abc",
  "product": {}
}

One other question is : - Is it right way for binding response model from dataset ?

Upvotes: 2

Views: 3083

Answers (2)

Shaiju T
Shaiju T

Reputation: 6609

My previous answer doesn't contribute to your final question. So here is my edited solution.

A Better Solution

May be better solution is using Custom Message Handler.

A delegating handler can also skip the inner handler and directly create the response.

Custom Message Handler:

public class NullJsonHandler : DelegatingHandler
    {
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {

            var updatedResponse = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = null
            };

            var response = await base.SendAsync(request, cancellationToken);

            if (response.Content == null)
            {
                response.Content = new StringContent("{}");
            }

            else if (response.Content is ObjectContent)
            {

                var contents = await response.Content.ReadAsStringAsync();

                if (contents.Contains("null"))
                {
                    contents = contents.Replace("null", "{}");
                }

                updatedResponse.Content = new StringContent(contents,Encoding.UTF8,"application/json");

            }

            var tsc = new TaskCompletionSource<HttpResponseMessage>();
            tsc.SetResult(updatedResponse);   
            return await tsc.Task;
        }
    }

Register the Handler:

In Global.asax file inside Application_Start() method register your Handler by adding below code.

GlobalConfiguration.Configuration.MessageHandlers.Add(new NullJsonHandler());

Now all the Asp.NET Web API Response which contains null will be replaced with empty Json body {}.

References:

1.

2.

Upvotes: 0

Marco
Marco

Reputation: 23937

the problem you are facing, is that you are initializing an instance of Product regardless of the fact, that there might be no product at all. this results, to its properties getting initialized with default values. Int32 defaults to 0. System.String as a reference type is null.

Profile_BO profile_BO = new Profile_BO();

foreach (DataRow dr in result.Tables[0].Rows)
{
    profile_BO.Id = Convert.ToInt32(dr[0]);
    profile_BO.Username = Convert.ToString(dr[1]);
}

//I am assuming you only expect one row, since oyur model uses a single Product
//and no collection of products. No need for a loop then.
if(result.Tables[1].Rows.Count == 1) { 
    Product product = new Product();
    var dr1 = result.Tables[1].Rows[0];

    product.Id = Convert.ToInt32(dr1[0]);
    product.Type = Convert.ToString(dr1[1]);

    profile_BO.product = product;
}

This should result in the following JSON being returned:

{
  "Id": "1",
  "Username": "abc",
  "product": null
}

EDIT: If you really must have product : {}, then you need ot change your model.

public class Profile_BO
{
    public int Id { get; set; }
    public string Username { get; set; }
    public object product { get; set; }

}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Declare product as an object. Since all classes inherit from object, you can instantiate it as an object or Product, depending on your case:

if(result.Tables[1].Rows.Count == 1) { 
    Product product = new Product();
    var dr1 = result.Tables[1].Rows[0];

    product.Id = Convert.ToInt32(dr1[0]);
    product.Type = Convert.ToString(dr1[1]);

    profile_BO.product = product;
}

Or:

if(result.Tables[1].Rows.Count == 0) { 
    var product = new object();    
    profile_BO.product = product;
}

This will then result in:

{"Id":1,"Username":"Foo Bar","product":{}}

However I strongly advise to go with the first approach, because this will make testing and modifications easier, since you keep your strongly typed approach.

Upvotes: 2

Related Questions