How to pass a collection of objects in a Refit query string? - c#

How can I format a collection of a custom class in the expected format for an API query string using Refit?
I've tried using various combinations of the Query / CollectionType / Format attributes.
Expected query string: http://someurl.com/api?Data[0].A=6&Data[0].B=7&Data[1].A=8&Data[1].B=9
Actual query string: http://someurl.com/api?Data=SomeClass%2CSomeClass
Full code using Refit.Newtonsoft.Json version 6.3.2 on .NET 4.6.1 (including outputting the request for debugging purposes):
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Refit;
public class SomeClass
{
public int A { get; set; }
public int B { get; set; }
}
public class Parameters
{
public IReadOnlyCollection<SomeClass> Data { get; set; }
}
public interface IClient
{
[Get("/api")]
Task<int> GetResult(Parameters parameters);
}
public class LoggingMessageHandler : DelegatingHandler
{
public LoggingMessageHandler(HttpMessageHandler innerHandler)
: base(innerHandler)
{
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Debug.WriteLine("Request:");
Debug.WriteLine(request.ToString());
if (request.Content != null)
{
Debug.WriteLine(await request.Content.ReadAsStringAsync());
}
return await base.SendAsync(request, cancellationToken);
}
}
public class Test
{
static void Main(string[] args)
{
var service = RestService.For<IClient>(
"http://someurl.com",
new RefitSettings
{
HttpMessageHandlerFactory = () => new LoggingMessageHandler(new HttpClientHandler())
}
);
var parameters = new Parameters()
{
Data = new SomeClass[] { new SomeClass() { A = 6, B = 7 }, new SomeClass() { A = 8, B = 9} }
};
var result = service.GetResult(parameters);
}
}

Related

JSONException:type java.lang.String cannot be converted to JSONArray

I am trying to fetch data from 000webhost server into my xamarin.android application. connection of php mysqldatabase is working good but I am getting JSONException in one of my classes shown below.
DataPhraser.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Java.Lang;
using Org.Json;
using Object = Java.Lang.Object;
using String = System.String;
namespace database_test.database.mySQL
{
class DataPhraser : AsyncTask
{
Context c;
private Spinner sp;
private String jsonData;
JavaList<string> Universities = new JavaList<string>();
private ProgressDialog pd;
public DataPhraser(Context c, Spinner sp, string jsonData)
{
this.c = c;
this.sp = sp;
this.jsonData = jsonData;
}
protected override void OnPreExecute()
{
base.OnPreExecute();
pd = new ProgressDialog(c);
pd.SetTitle("Parse Data");
pd.SetMessage("Parsing Data..... Please Wait");
pd.Show();
}
protected override Object DoInBackground(params Object[] #params)
{
//throw new NotImplementedException();
return this.ParseData();
}
protected override void OnPostExecute(Object result)
{
base.OnPostExecute(result);
pd.Dismiss();
if (Integer.ParseInt(result.ToString()) == 0)
{
Toast.MakeText(c, "unable to Prase", ToastLength.Short).Show();
}
else
{
ArrayAdapter<string> adapter = new ArrayAdapter<string>(c, Android.Resource.Layout.SimpleListItem1, Universities);
sp.Adapter = adapter;
sp.ItemSelected += sp_ItemSelected;
}
}
private void sp_ItemSelected(object sender, AdapterView.ItemSelectedEventArgs e)
{
Toast.MakeText(c, Universities[e.Position], ToastLength.Short).Show();
}
private int ParseData()
{
try
{
JSONArray ja = new JSONArray(jsonData);
JSONObject jo = null;
Universities.Clear();
for (int i = 0; i < ja.Length(); i++)
{
jo = ja.GetJSONObject(i);
String name = jo.GetString("Country");
Universities.Add(name);
}
return 1;
}
catch (System.Exception e)
{
Console.WriteLine(e);
}
return 0;
}
}
}
I am getting error at " JSONArray ja = new JSONArray(jsonData)" this point of the code.
Mysqldatabase is
According to your gson, you can try to use Newtonsoft.Json Nuget ,for example:
namespace QuickType
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class Welcome
{
[JsonProperty("Options")]
public Option[] Options { get; set; }
}
public partial class Option
{
[JsonProperty("ID")]
public long Id { get; set; }
[JsonProperty("University Name")]
public string UniversityName { get; set; }
[JsonProperty("Country")]
public string Country { get; set; }
[JsonProperty("Course")]
public string Course { get; set; }
[JsonProperty("Field of Study")]
public string FieldOfStudy { get; set; }
[JsonProperty("Course Language")]
public string CourseLanguage { get; set; }
[JsonProperty("Type of Institution")]
public string TypeOfInstitution { get; set; }
}
public partial class Welcome
{
public static Welcome FromJson(string json) => JsonConvert.DeserializeObject<Welcome>(json, QuickType.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this Welcome self) => JsonConvert.SerializeObject(self, QuickType.Converter.Settings);
}
internal static class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters =
{
new IsoDateTimeConverter { DateTimeStyles =
DateTimeStyles.AssumeUniversal }
},
};
}
}
For more details, you can check: https://app.quicktype.io/#l=cs&r=json2csharp
Note: you can just copy your json string to the left part of above link, then it will convert the json into relative data models.

Wrap all api response in one object for .net core REST web api

Using .net core API
I have one response object that I use
for all responses (POST,PUT DELETE,GET):
public class CResponse
{
public object d { get; private set; }
public string ErrorMsg { get; private set; }
public CResponse(object d, string errorMsg)
{
this.d = d;
ErrorMsg = errorMsg;
}
public static CResponse Generate(object d, string errorMsg = null)
{
return new CResponse(d, errorMsg);
}
}
This is how I use it on a POST for example:
public async Task<IActionResult> Post([FromBody] CCampaignDto campaignAddDto)
{
CCampaignAdd cCampaignAdd = new CCampaignAdd(campaignAddDto);
return Created(string.Empty, CResponse.Generate(await cCampaignAdd.SaveChangesAsync()));
}
PUT :
public async Task<IActionResult> Put([FromBody] CCampaignDto campaignAddDto)
{
CCampaignUpdate campaignUpdate = new CCampaignUpdate(campaignAddDto);
return Accepted(CResponse.Generate(await campaignUpdate.SaveChangesAsync()));
}
What can I do to wrap all api response with this class
instead of using it on each POST,PUT,DELETE.
Thanks
this is how i did it using JsonOutputFormatter
created a custom class:
public class CustomJsonOutputFormatter : JsonOutputFormatter
{
public CustomJsonOutputFormatter(JsonSerializerSettings serializerSettings, ArrayPool<char> charPool)
: base(serializerSettings, charPool)
{ }
public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
{
var #object = CResponse.Generate(context.Object, (HttpStatusCode)context.HttpContext.Response.StatusCode);
var newContext = new OutputFormatterWriteContext(context.HttpContext, context.WriterFactory, typeof(CResponse), #object);
newContext.ContentType = context.ContentType;
newContext.ContentTypeIsServerDefined = context.ContentTypeIsServerDefined;
return base.WriteResponseBodyAsync(newContext, selectedEncoding);
}
}
than on startup.cs
var jsonSettings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
};
services.AddMvc(options =>
{
options.OutputFormatters.RemoveType<JsonOutputFormatter>();
options.OutputFormatters.Add(new CustomJsonOutputFormatter(jsonSettings, ArrayPool<char>.Shared));
})

Using MessagePack with AspNet Core WebAPI and Console App

I am currently trying to implement MessagePack in a solution which contains 2 projects : AspNet Core WebAPI and a simple console app. The following package was added :
How fo I Deserialize the object back on the client, here is the code snippets, also when Posting back an object from the client to the api, do I just Serialize on the client and send it to the Post method in the api, which will take a string, take the string and Deserialize it again, I will need to pass the type somehow to the controller also.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MessagePack;
using Microsoft.AspNetCore.Mvc;
namespace WebApplication1.Controllers
{
[Route("api/[controller]")]
public class ValuesController : Controller
{
[HttpGet]
public IActionResult Get()
{
var results = new List<Superhero>();
results.Add(new Superhero { HeroID = 1, HeroName = "Bruce Wayne" });
results.Add(new Superhero { HeroID = 2, HeroName = "Selina Kyle" });
results.Add(new Superhero { HeroID = 3, HeroName = "Clark Kent" });
var bytes = MessagePackSerializer.Serialize(results);
return Ok(bytes);
}
[HttpGet("{id}")]
public string Get(int id)
{
return "value";
}
[HttpPost]
public void Post([FromBody]string value)
{
// how to I Deserialize here ? what do I just post from client to
// with the Serialized object and pass the type also ???
}
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
[MessagePackObject]
public class Superhero
{
[Key(0)]
public int HeroID { get; set; }
[Key(1)]
public string HeroName { get; set; }
}
}
using MessagePack;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace MessagePackExampleOne
{
class Program
{
static HttpClient client = new HttpClient();
static void Main(string[] args)
{
client.BaseAddress = new Uri("http://localhost:57752");
client.DefaultRequestHeaders.Accept.Clear();
HttpResponseMessage response = client.GetAsync("/api/values").Result;
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync().Result;
//how to Deserialize this objec ??
// Console.WriteLine(MessagePackSerializer.ToJson(result));
// var mc2 = MessagePackSerializer.Deserialize<List<Superhero>>(result);
}
Console.Read();
}
}
[MessagePackObject]
public class Superhero
{
[Key(0)]
public int HeroID { get; set; }
[Key(1)]
public string HeroName { get; set; }
}
}
to send something in post method from client use TryAddWithoutValidation:
var x = MessagePackSerializer.Serialize(MyCLassObj to send);
var content = new ByteArrayContent(x);
content.Headers.TryAddWithoutValidation("Content-Type", "application/x-msgpack");
httpResponse = await httpClient.PostAsync("/api...", content,token);

Xamarin API VK List forming

I'm trying to do qualification job for a work and have some problems with realization of code on Xamarin.
I have such classes and functions. They're working on console of c# but not in xamarin. I don't know what to do. They give only freeze on Xamarin.
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace radacode.ActionForm
{
class ListMaker
{
public static List<Country> GetCountryList()
{
List<Country> result=new List<Country>();
Task<string> task =GetRequestAsync(#"http://api.vk.com/method/database.getCountries?need_all=1&v=5.60");
JObject vk = JObject.Parse(task.GetAwaiter().GetResult());
foreach (JObject jsonCountry in vk["response"]["items"])
result.Add(JsonConvert.DeserializeObject<Country>(jsonCountry.ToString()));
return result;
}
public static async Task<string> GetRequestAsync(string url)
{
using (var httpClient = new HttpClient())
return await httpClient.GetStringAsync(url);
}
public class Country
{
public int Cid { get; set; }
public string Title { get; set; }
override public string ToString()
{
return Title;
}
}
}
}
When using Xamarin Forms, it's best to use Portable Class Projects rather than Shared. In my opinion.
Also it's important that Statics are not used especially for calls that are async. Think of Async as to being similar to AsyncTask in JAVA. They're none blocking.
public class ListMaker
{
public List<Country> GetCountyList()
{
return GetCountryListAsync().Result;
}
private async Task<List<Country>> GetCountryListAsync()
{
var result = new List<Country>();
var task =
await GetRequestAsync(#"http://api.vk.com/method/database.getCountries?need_all=1&v=5.60");
var vk = JObject.Parse(task);
foreach (var jsonCountry in vk["response"]["items"])
result.Add(JsonConvert.DeserializeObject<Country>(jsonCountry.ToString()));
return result;
}
private async Task<string> GetRequestAsync(string url)
{
using (var httpClient = new HttpClient())
return await httpClient.GetStringAsync(url);
}
public class Country
{
public int Cid { get; set; }
public string Title { get; set; }
public new string ToString()
{
return Title;
}
}
}
Now that you have your class, you can then create an instance of it and execute it.
NOTE:- the Async and Await in my example, or this one, is incorrect.
It should really bubble up to a parent class that has a property and a void in the class statement.
public async void TheLister()
{
var listMaker = new ListMaker();
var countryList = await listmaker.GetCountryListAsync();
// Do something with countryList
}

How can i mock method that has HtttpRequestBase parameter

I have method:
public override someClass getX(HttpRequestBase request){ ... }
now, I want to mock it.
I tried
mockProvider.Setup(x => x.getX(It.IsAny<HttpRequestWrapper>())).Returns(someClassInstance);
but it return null, not someClassInstance (by debug i can see it's not null).
what can i do? thanks!
I don't exactly understand why you expecte the result to be "2" nor can i see the declaration of someClassInstance to verify if the Assert should or should not be NULL.
However, I implemented those Methods and wrapped a test around:
using System.Web;
using Moq;
using NUnit.Framework;
public class FooBase
{
public virtual ResultObject getX(HttpRequestBase request)
{
return new ResultObject { Id = 2 };
}
}
public class Foo : FooBase
{
public override ResultObject getX(HttpRequestBase request)
{
return new ResultObject { Id = 4 };
}
}
public class ResultObject
{
public int Id { get; set; }
}
[TestFixture]
public class Test
{
Mock<Foo> mockProvider = new Mock<Foo>();
[Test]
public void FooTest()
{
// Arrange
var fakedResultObject = new ResultObject { Id = 8 };
mockProvider.Setup(x => x.getX(It.IsAny<HttpRequestWrapper>())).Returns(fakedResultObject);
// Act
var result = mockProvider.Object.getX(new HttpRequestWrapper(new HttpRequest("filename", "http://foo.org", "querystring")));
//Assert
Assert.AreEqual(8, result.Id);
}
}

Categories