rechigo 293 Posted February 10, 2020 Share Posted February 10, 2020 (edited) After an hour of trying to figure out why sending my HTTP request would error with BadRequest, I figured it out, however I don't know how to fix it. Basically, to set post data you need to a dictionary of strings, which is the problem here. For the embed key, the value(array of embeds) keeps getting wrapped in quotes because it's a dictionary of strings, makes sense. The problem is the Discord API isn't expecting the array wrapped in quotes: {"embeds":"[{\"color\":1222617,\"title\":\"It works!\",\"description\":\"This is a test notification from Emby\"}]","username":"MBCord","avatar_url":"https://i.imgur.com/4k4fUmy.png"} it's expecting the embed array like this (not in quotes): {"embeds":[{\"color\":1222617,\"title\":\"It works!\",\"description\":\"This is a test notification from Emby\"}],"username":"MBCord","avatar_url":"https://i.imgur.com/4k4fUmy.png"} But since I'm putting my array in a dictionary of strings, it wraps my array in quotes causing the Discord API to return a 400 How can I do this without my array getting wrapped in quotes before it's sent? Relevant code: var options = GetOptions(request.UserID); List<DiscordEmbed> Embeds = new List<DiscordEmbed> { }; Embeds.Add(new DiscordEmbed { color = int.Parse(options.EmbedColor.Substring(1, 6), System.Globalization.NumberStyles.HexNumber), title = "It works!", description = "This is a test notification from Emby" }); var parameters = new Dictionary<string, string> { }; parameters.Add("embeds", _jsonSerializer.SerializeToString(Embeds)); parameters.Add("username", options.Username); parameters.Add("avatar_url", options.AvatarUrl); _logger.Debug("Discord Request to: {0} From: {1} With: {2}", options.DiscordWebhookURI, _userManager.GetUserById(request.UserID).Name, _jsonSerializer.SerializeToString(parameters)); var httpRequestOptions = new HttpRequestOptions { }; httpRequestOptions.Url = options.DiscordWebhookURI; httpRequestOptions.RequestHeaders["Content-Type"] = "application/json"; httpRequestOptions.SetPostData(parameters); using (await _httpClient.Post(httpRequestOptions).ConfigureAwait(false)) { } I'm new to C# so please bear with me Edited February 11, 2020 by rechigo Link to comment Share on other sites More sharing options...
Luke 37062 Posted February 10, 2020 Share Posted February 10, 2020 @@chef have you tried this? Link to comment Share on other sites More sharing options...
chef 3745 Posted February 11, 2020 Share Posted February 11, 2020 Two things come to mind here. First you could try Dictionary<string, object> Or Dictionary<string, DiscordEmbed> Without seeing a little more it's only a guess. I haven't had a great deal of success serializing dictionaries into json data. I have had to use List<List<T>> in the past. Would you want to share your work with me then I could be a bit more helpful. Is there some API docs to scan over to better understand the object types in the json data? Link to comment Share on other sites More sharing options...
rechigo 293 Posted February 11, 2020 Author Share Posted February 11, 2020 Two things come to mind here. First you could try Dictionary<string, object> Or Dictionary<string, DiscordEmbed> Without seeing a little more it's only a guess. I haven't had a great deal of success serializing dictionaries into json data. I have had to use List<List<T>> in the past. Would you want to share your work with me then I could be a bit more helpful. Is there some API docs to scan over to better understand the object types in the json data? I created a DiscordMessage class which also implements DiscordEmbed, however I can't do something like Dictionary<string, DiscordMessage> as SetPostData expects a Dictionary<string, string> Here is the official documentation on executing webhooks: https://discordapp.com/developers/docs/resources/webhook#execute-webhook If you want to see the code, I can send you the github repo when I get home and push to it Sent from my SM-G973U using Tapatalk Link to comment Share on other sites More sharing options...
chef 3745 Posted February 12, 2020 Share Posted February 12, 2020 (edited) Try this: public class Embed { public int color { get; set; } public string title { get; set; } public string description { get; set; } } public class PostData { public List<Embed> embeds { get; set; } public string username { get; set; } public string avatar_url { get; set; } } public string getPostDataJson(MY_VARS_HERE) { return JsonSerializer.SerializeToString(new PostData() { avatar_url = "MY_URL", username = "MY_USER_NAME", embeds = new List<Embed>() { new Embed() { color = 18181818, //My_COLOR_INT description = "MY_DESCRIPTION", title = "MY_TITLE" } //You could add another embeded item here inside the list. } }); } Use: var postData = getPostDataJson(My_VARS_HERE) Try to send that as postData. The thing is, C# Dictionaries aren't really a thing (... I mean it's possible but they are not the same... really.... ) in JSON. You have to create classes and have Lists<T> inside them. In order to get a jump start on turning JSON data requirements into C# Classes check out this site, it will change your coding life! http://json2csharp.com/ Let me know how it goes! Edited February 12, 2020 by chef Link to comment Share on other sites More sharing options...
rechigo 293 Posted February 13, 2020 Author Share Posted February 13, 2020 Try this: public class Embed { public int color { get; set; } public string title { get; set; } public string description { get; set; } } public class PostData { public List<Embed> embeds { get; set; } public string username { get; set; } public string avatar_url { get; set; } } public string getPostDataJson(MY_VARS_HERE) { return JsonSerializer.SerializeToString(new PostData() { avatar_url = "MY_URL", username = "MY_USER_NAME", embeds = new List<Embed>() { new Embed() { color = 18181818, //My_COLOR_INT description = "MY_DESCRIPTION", title = "MY_TITLE" } //You could add another embeded item here inside the list. } }); } Use: var postData = getPostDataJson(My_VARS_HERE) Try to send that as postData. The thing is, C# Dictionaries aren't really a thing (... I mean it's possible but they are not the same... really.... ) in JSON. You have to create classes and have Lists<T> inside them. In order to get a jump start on turning JSON data requirements into C# Classes check out this site, it will change your coding life! http://json2csharp.com/ Let me know how it goes! This makes sense, but how am I supposed to set postData as my post data when the SetPostData method only accepts Dictionary<string,string>? Link to comment Share on other sites More sharing options...
chef 3745 Posted February 13, 2020 Share Posted February 13, 2020 (edited) try { await _httpClient.Post( new HttpRequestOptions { Url = "", CancellationToken = CancellationToken.None, EnableHttpCompression = false, RequestContent = JSON_CONTENT_HERE_MAYBE }) .ConfigureAwait(false); } catch { } } Please try this. But, I'm not entirely sure. If this doesn't work, let me know, and I'll keep reading Github to find an example as a sure thing. What happens if you place the serialized jsonData inside SetPostData() httpRequestOptions.SetPostData(SERIALIZED_JSON_HERE); Edited February 13, 2020 by chef Link to comment Share on other sites More sharing options...
rechigo 293 Posted February 13, 2020 Author Share Posted February 13, 2020 What happens using SetPostData with postData as the data what happens when using RequestContent Link to comment Share on other sites More sharing options...
rechigo 293 Posted February 13, 2020 Author Share Posted February 13, 2020 (edited) OKAY, I finally got it working, but there's one catch: I'm have to use the System.Net HttpClient, not Emby's IHttpClient... var postData = new StringContent(_jsonSerializer.SerializeToString(new DiscordMessage() { avatar_url = options.AvatarUrl, username = options.Username, embeds = new List<DiscordEmbed>() { new DiscordEmbed() { color = 181818, description = "That's RIGHT", title = "HA" } } }).ToString()); try { var RequestMessage = new HttpRequestMessage(HttpMethod.Post, options.DiscordWebhookURI); RequestMessage.Content = postData; RequestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); await _httpClient.SendAsync(RequestMessage).ConfigureAwait(false); } catch (HttpRequestException e) { _logger.Error("Failed to make request to Discord: {0}", e); } Edited February 13, 2020 by rechigo 1 Link to comment Share on other sites More sharing options...
chef 3745 Posted February 13, 2020 Share Posted February 13, 2020 OKAY, I finally got it working, but there's one catch: I'm have to use the System.Net HttpClient, not Emby's IHttpClient... var postData = new StringContent(_jsonSerializer.SerializeToString(new DiscordMessage() { avatar_url = options.AvatarUrl, username = options.Username, embeds = new List<DiscordEmbed>() { new DiscordEmbed() { color = 181818, description = "That's RIGHT", title = "HA" } } }).ToString()); try { var RequestMessage = new HttpRequestMessage(HttpMethod.Post, options.DiscordWebhookURI); RequestMessage.Content = postData; RequestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); await _httpClient.SendAsync(RequestMessage).ConfigureAwait(false); } catch (HttpRequestException e) { _logger.Error("Failed to make request to Discord: {0}", e); } Well done! 1 Link to comment Share on other sites More sharing options...
chef 3745 Posted February 13, 2020 Share Posted February 13, 2020 (edited) As a side note, in your project you have to add a nuget package to be able to use 'AsMemory'. System.Memory Edited February 13, 2020 by chef Link to comment Share on other sites More sharing options...
mickle026 400 Posted March 13, 2020 Share Posted March 13, 2020 (edited) I need to learn c# ..... This might or might not be relevant, but just so you know... In vb.net if you do a string array of strings , ie dictionary <string,string> you get the data wrapped in quotes. What you do is create an array of strings, not a string array of strings - if that makes sense. Your dictionary array looks like a standard 2d array in vb.net, but its not. However you can use them the same so in vb. it would be, Dim MyArray(,)={{"1st element key","1st element data"},{"2nd element key","2nd element data"}, .... and so on } I think in c# it would be like this .... string[,] array = new string[,] { {"1st element key", "1st element data"}, {"2nd element ke", "2nd element data"}, }; This array shouldn't wrap the string in quotes.. Edited March 13, 2020 by mickle026 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now