Forgive my lack of knowlegde, I'm a database guy although I dabbled a bit with C# a while back. I am trying to figure how to get this API running.
The API I'm trying to consume is from https://rapidapi.com/api-sports/api/api-nba/. There is barely any documentation to guide me.
Here's my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using unirest_net.http;
using unirest_net;
namespace NBA_test
{
class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Start ...");
Task<HttpResponse<MyClass.RootObject>> response = Unirest.get("https://api-nba-v1.p.rapidapi.com/gameDetails/5162")
.header("X-RapidAPI-Host", "api-nba-v1.p.rapidapi.com")
.header("X-RapidAPI-Key", "myKey")
.asJsonAsync<MyClass.RootObject>();
var status = response.Status;
Console.WriteLine("End ....");
}
}
public class MyClass
{
public class Result
{
public string seasonYear { get; set; }
public int gameId { get; set; }
public string arena { get; set; }
}
public class RootObject
{
public List<Result> results { get; set; }
}
}
}
var status goes from Created to Running and then that's it, program closes. No error message but I don't know how to get the JSON out of this API. I know I'm missing something but don't know what.
You are in a console application with a sync main method. You should not call an async method inside a sync method. I made your async call into a sync call :
public static void Main(string[] args)
{
Console.WriteLine("Start ...");
var response = Unirest.get("https://api-nba-v1.p.rapidapi.com/gameDetails/5162")
.header("X-RapidAPI-Host", "api-nba-v1.p.rapidapi.com")
.header("X-RapidAPI-Key", "myKey")
.asJson<RootObject>();
var status = response.Status;
Console.WriteLine("End ....");
}
you still might ask where is your deserialized JSON?
According to Unirest docs:
Response
Upon recieving a response Unirest returns the result in the
form of an Object, this object should always have the same keys for
each language regarding to the response details.
.Code - HTTP Response Status Code (Example 200)
.Headers - HTTP
Response Headers
.Body - Parsed response body where applicable, for
example JSON responses are parsed to Objects / Associative Arrays.
.Raw - Un-parsed response body
Basically, you can access your result like this:
if (response.Code == 200) // Success, OK in HTTP Codes
{
response.Body; // which body has the type of MyClass.RootObject
}
The complete example:
public static void Main(string[] args)
{
Console.WriteLine("Start ...");
var response = Unirest.get("https://api-nba-v1.p.rapidapi.com/gameDetails/5162")
.header("X-RapidAPI-Host", "api-nba-v1.p.rapidapi.com")
.header("X-RapidAPI-Key", "myKey")
.asJson<RootObject>();
if (response.Code == 200) // Success, OK in HTTP Codes
{
response.Body; // which body has the type of MyClass.RootObject
}
Console.WriteLine("End ....");
Console.ReadLine(); // to force command line stay up for an input and not close applicaiton immediately aftter runing it.
}
Update 1:
Here is a live and working of Unirest on .NET Fiddle:
https://dotnetfiddle.net/EZDopa
You can use httpClient
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36");
var response = httpClient.GetStringAsync(new Uri(url)).Result;
var releases = JArray.Parse(response);
}
As the others pointed out you need to add some kinda wait statment. I did many calls to api that took time to process in one of my applications. Based on the others comments I updated to allow for logic to be executed while your waiting for the call to come back. an edit for your code is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using unirest_net.http;
using unirest_net;
namespace NBA_test
{
class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Start ...");
//the added Wait() causes the thread to hold until the task is finished.
Task<HttpResponse<MyClass.RootObject>> response = Unirest.get("https://api-nba-v1.p.rapidapi.com/gameDetails/5162")
.header("X-RapidAPI-Host", "api-nba-v1.p.rapidapi.com")
.header("X-RapidAPI-Key", "myKey")
.asJsonAsync<MyClass.RootObject>();
//if need to perform other logic while you are waiting
while(response.Status == TaskStatus.Running)
{
// perform other logic like gui here
}
var status = response.Status;
Console.WriteLine("End ....");
}
}
public class MyClass
{
public class Result
{
public string seasonYear { get; set; }
public int gameId { get; set; }
public string arena { get; set; }
}
public class RootObject
{
public List<Result> results { get; set; }
}
}
}
Turns out the API's documentation is flawed. I managed to make it work by simply using string (and Newtonsoft's Json.NET). Thx for the help #AliBahrami. Code looks like this now:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using unirest_net.http;
using unirest_net;
using Newtonsoft.Json.Linq;
namespace NBA_test
{
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Start of Program...");
HttpResponse<string> response = Unirest.get("https://api-nba-v1.p.rapidapi.com/gameDetails/9999")
.header("X-RapidAPI-Host", "api-nba-v1.p.rapidapi.com")
.header("X-RapidAPI-Key", "myKey")
.asJson<string>();
var result = response.Body;
JObject parsedString = JObject.Parse(result);
RootObject myGame = parsedString.ToObject<RootObject>();
// Get game id
Console.WriteLine(myGame.results[0].gameId);
Console.WriteLine("End of Program....");
}
}
}
Related
I'm very close to implementing a system in C# which allows me to send a push-notification with the click of a button from an interface written in ASP.net to a C# console application acting as client. This all using WebSockets.
After reading a lot of tutorials and reusing code found online I'm already able to successfully establish a WebSocket connection. I'm yet not able to actually send a Notification.
The part I'm struggling with is the function that get's triggered as soon as a button is clicked:
//Close ticket and send push-notification over websocket
public void Close(int id) {
//Ticket ticket = mgr.GetTicket(id);
//Create a new notification
Notification notif = new Notification();
notif.message = "Rofl test123 Notification lol";
//Initialize WebSocketMiddleware here??
//WebSocketsMiddleware wsm = new WebSocketsMiddleware(what parameter??);
//wsm.Invoke(what HttpContext parameter???)
NotificationManager notifMgr;
//notifMgr.AddSubscriber(wsm);
//notifMgr.SendNotificationAsync(notif);
return;
}
The specific questions/problems I'm encountering are:
How to initialize the class WebSocketsMiddleware? Does it need to be initialized, if yes, what is the parameter with type RequestDelegate? What do I pass to that parameter?
WebSocketsMiddleware has an Invoke function with parameter context of type HttpContext. Do I just need to pass new HttpContext() to this? Is that sufficient?
Someone made a class NotificationManager, this class uses the middleware to actually send a notification. Do I just need to pass the initialized WebSocketsMiddleware variable as parameter for NotificationManager.AddSubscriber()? Will the notifications of each client be nicely separated then?
Can I after that just use SendNotificationAsync() to send the notification?
Bonus question: Say that each client has it's own button. When I click a client's button only that client may receive a push-notification. How to make sure that all the other client's don't receive the same notification as well?
To be able to help me with these questions you'll need the following classes. The question is merely about WebSockets but more about how to initiate and use the classes I gathered from the tutorials.
Notification.cs - Class representing a Notification (notification text, send-date,...):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace SC.UI.MVC.Models
{
public class Notification
{
public Guid? notificationId { get; set; }
public int id { get; set; }
public DateTime timestamp { get; set; }
public string message { get; set; }
public string type { get; set; }
public Notification()
{
// add a new guid as a unique identifier for the notification in the db
notificationId = Guid.NewGuid();
}
}
}
WebSocketsMiddleware.cs - Has the low-level part of the WebSockets handled, invoking connection etc:
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
namespace NotificationsApi.Notifications
{
public class WebSocketsMiddleware
{
// private variable to track the next delegate to call in the request chain
private readonly RequestDelegate _next;
public WebSocketsMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
CancellationToken ct = context.RequestAborted;
string currentSubscriberId = null;
WebSocket currentSocket = null;
// we want to listen on a specific path for websocket communications
if (context.Request.Path == "/notifications/ws")
{
// make sure the request is a websocket request
if (context.WebSockets.IsWebSocketRequest)
{
currentSocket = await context.WebSockets.AcceptWebSocketAsync();
currentSubscriberId = NotificationManager.Instance.AddSubscriber(currentSocket);
// keep the socket open until we get a cancellation request
while (true)
{
if (ct.IsCancellationRequested)
{
break;
}
}
}
else // return an HTTP bad request status code if anything other a web socket request is made on this URI
{
context.Response.StatusCode = 400;
}
}
// clean up the socket
if (!string.IsNullOrWhiteSpace(currentSubscriberId))
{
NotificationManager.Instance.RemoveSubscriber(currentSubscriberId);
if (currentSocket != null)
{
await currentSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
currentSocket.Dispose();
}
}
// call the next delegate in the pipeline
await _next(context);
return;
}
}
}
NotificationManager.cs - Interface/Class with three functions to add and remove subscribers, and to actually send a notification. Uses the WebSocket middleware to achieve this:
using SC.UI.MVC.Models;
//using NotificationsApi.Persistence;
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace NotificationsApi.Notifications
{
// interface for NotificationManager for dependency injection
public interface INotificationManager
{
string AddSubscriber(WebSocket subscriber);
void RemoveSubscriber(string subscriberId);
Task SendNotificationAsync(Notification notification);
}
public class NotificationManager : INotificationManager
{
// static instance of the NotificationManager class
private static INotificationManager _instance;
public static INotificationManager Instance { get { return _instance ?? (_instance = new NotificationManager()); } set { _instance = value; } }
// static dictionary to keep track of all notification subscribers
private static ConcurrentDictionary<string, WebSocket> _subscribers = new ConcurrentDictionary<string, WebSocket>();
// adds a subscriber to receive notifications
public string AddSubscriber(WebSocket subscriber)
{
var subscriberId = Guid.NewGuid().ToString();
_subscribers.TryAdd(subscriberId, subscriber);
return subscriberId.ToString();
}
// removes a notifications subscriber
public void RemoveSubscriber(string subscriberId)
{
WebSocket empty;
_subscribers.TryRemove(subscriberId, out empty);
}
// sends a notification to all subscribers
public async Task SendNotificationAsync(Notification notification)
{
// add the notification to the persistence store
//await PersistenceManager.Instance.AddNotificationAsync(notification);
// send the notification to all subscribers
foreach (var s in _subscribers)
{
if (s.Value.State == WebSocketState.Open)
{
var jsonNotification = JsonConvert.SerializeObject(notification);
await SendStringAsync(s.Value, jsonNotification);
}
}
}
// sends a string via web socket communication
private async Task SendStringAsync(WebSocket socket, string data, CancellationToken ct = default(CancellationToken))
{
var buffer = Encoding.UTF8.GetBytes(data);
var segment = new ArraySegment<byte>(buffer);
await socket.SendAsync(segment, WebSocketMessageType.Text, true, ct);
}
}
}
Client.cs - Client receiving the push-notification. Not really a problem here I guess:
/* WEBSOCKET PART */
//Variables for websocket
private static object consoleLock = new object();
private const int sendChunkSize = 256;
private const int receiveChunkSize = 256;
private const bool verbose = true;
private static readonly TimeSpan delay = TimeSpan.FromMilliseconds(30000);
//Function to check if a ticket from this client is closed/solved
public void checkTicketSolved() {
Thread.Sleep(1000);
Connect("ws://localhost:5050/notifications/ws").Wait();
Console.WriteLine("Press any key to exit...");
}
public static async Task Connect(string uri)
{
ClientWebSocket webSocket = null;
try
{
webSocket = new ClientWebSocket();
await webSocket.ConnectAsync(new Uri(uri), CancellationToken.None);
await Task.WhenAll(Receive(webSocket), Send(webSocket));
}
catch (Exception ex)
{
Console.WriteLine("Exception: {0}", ex);
}
finally
{
if (webSocket != null)
webSocket.Dispose();
Console.WriteLine();
lock (consoleLock)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("WebSocket closed.");
Console.ResetColor();
}
}
}
static UTF8Encoding encoder = new UTF8Encoding();
private static async Task Send(ClientWebSocket webSocket)
{
//byte[] buffer = encoder.GetBytes("{\"op\":\"blocks_sub\"}"); //"{\"op\":\"unconfirmed_sub\"}");
byte[] buffer = encoder.GetBytes("{\"op\":\"unconfirmed_sub\"}");
await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
while (webSocket.State == WebSocketState.Open)
{
LogStatus(false, buffer, buffer.Length);
await Task.Delay(delay);
}
}
private static async Task Receive(ClientWebSocket webSocket)
{
byte[] buffer = new byte[receiveChunkSize];
while (webSocket.State == WebSocketState.Open)
{
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Close)
{
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
}
else
{
LogStatus(true, buffer, result.Count);
}
}
}
private static void LogStatus(bool receiving, byte[] buffer, int length)
{
lock (consoleLock)
{
Console.ForegroundColor = receiving ? ConsoleColor.Green : ConsoleColor.Gray;
//Console.WriteLine("{0} ", receiving ? "Received" : "Sent");
if (verbose)
Console.WriteLine(encoder.GetString(buffer));
Console.ResetColor();
}
}
}
You can also find this code on Github.
The relevant parts of the code are located in:
WebServer/UI-MVC/Controllers/TicketController.cs -> Contains function triggered when a button is clicked.
WebServer/UI-MVC/Notifications -> Contains NotificationManager.cs and WebSocketsMiddleware.cs
WebServer/UI-MVC/Models -> Contains Notification.cs
Client/ contains all the code for the client's console application
To give you some context about the application:
This application represents a ticketing system which allows clients/customers which use my software to open support tickets. The WebServer-part is for administrators/employees of me to answer and manage tickets. The Console Application is what my customers/clients need to have installed in order to contact my support service and open a support ticket. When an administrator closes the ticket of a client by clicking a button, it means the ticket and thus the client's problem was resolved and closed. Resulting in the client getting a push-notification about that.
I am not looking for references to other tutorials about WebSockets or suggestions using SignalR instead or whatever, I've already read all of them and I've already used SignalR but am interested in pure WebSockets now. I would be very grateful for someone who could help me working out the first part of code posted in this question (the Close-function) and explains what he has done. Thanks!
I found the solution myself.
First I made a new controller called NotificationsController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using SC.UI.MVC.Models;
using NotificationsApi.Notifications;
//using NotificationsApi.Persistence;
using System.Net.Http;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace NotificationsApi.Controllers
{
[Route("api/notifications")]
public class NotificationsController : Controller
{
// GET api/notifications
[HttpGet]
public ActionResult Get()
{
try
{
var notifications = new List<Notification>();
//notifications = PersistenceManager.Instance.GetNotifications();
return Ok(notifications);
}
catch (Exception exception)
{
// log exception
// TODO: implement logging
// return a 500
return StatusCode(500);
}
}
// POST api/notifications
[HttpPost]
public async Task<ActionResult> Post(string message)
{
Notification notification = new Notification();
notification.message = message;
Console.WriteLine(message);
try
{
// return a 400 if we didn't get a valid json payload in the body
if (notification == null)
return BadRequest();
await NotificationManager.Instance.SendNotificationAsync(notification);
// we aren't returning the object to reference because POSTing a notification is fire and forget
return Created(string.Empty, null);
}
catch (Exception exception)
{
// log the error
// TODO: implement logging
// return a 500
return StatusCode(500);
}
return Ok();
}
}
}
Then I commented out the unnecessary properties in Notification.cs so only Guid and message remain. Now I'm able to just send a notification by calling the NotificationsController with a POST request carrying the message-parameter as data.
12 hours ago (around dinner time here in Texas), it was working just fine at a moment when I hope the latency to be very high because of the high traffic.
Any idea why this could be happening and how to troubleshoot this issue?
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Nancy.Json;
namespace Training.Threading
{
class TasksDemo
{
static async Task Main(string[] args)
{
Post[] posts = await GetPostsAsync();
foreach(Post post in posts)
System.Console.WriteLine(post.Title);
}
public static Task<Post[]> GetPostsAsync() => Task.Run(() =>
{
var json = new WebClient().DownloadString("https://jsonplaceholder.typicode.com/posts");
JavaScriptSerializer ser = new JavaScriptSerializer();
var posts = ser.Deserialize<Post[]>(json);
return posts;
});
}
public class Post
{
public int UserId { get; set; }
public string Title { get; set; }
public string Body { get; set; }
}
}
I don't think the code is the issue here. It is more so your ISP or the bandwith available to the server / traffic you are trying to contact.
Some tools that will help you diagnose the issue specifically in windows to spot your issue include
'tracert' (trace route)
'ping' (ping)
In Windows:
ping jasonplaceholder.typicode.com
To view latency between "hops"
tracert jsonplaceholder.typicode.com
this will provide in milliseconds the latency to the server you are trying to reach assuming they respond to ping request ICMP.
Following the advice fo #maccettura and #ckuri I'm using now HttpClient, I thought I'd be good to post the code here.
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Nancy.Json;
namespace Training.Threading
{
class TasksDemo
{
static async Task Main(string[] args)
{
string json = await GetPostsAsync();
// System.Console.WriteLine(json);
JavaScriptSerializer ser = new JavaScriptSerializer();
var posts = ser.Deserialize<Post[]>(json);
foreach(Post post in posts)
System.Console.WriteLine(post.Title);
}
public static async Task<string> GetPostsAsync()
{
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(#"https://jsonplaceholder.typicode.com");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return await client.GetStringAsync("/posts");
}
}
}
public class Post
{
public int UserId { get; set; }
public string Title { get; set; }
public string Body { get; set; }
}
}
hello guys i have swagger url http://somehost/swagger/index.html
end methods there as shown on image:
I am trying to create HTTP POST web request refer to one of the post method.
using System;
using System.Collections.Generic;
using System.Net.Http;
namespace SwaggerConsoleAPP
{
class Program
{
static void Main(string[] args)
{
postRequest("http://somehost/api/Referral/GetReferralsByPersonalIdNumber");
Console.ReadKey();
}
async static void postRequest (string url){
IEnumerable<KeyValuePair<string, string>> queries = new List<KeyValuePair<string, string>>() {
new KeyValuePair<string, string>("1133221221","5642")
};
HttpContent q = new FormUrlEncodedContent(queries);
using (HttpClient client = new HttpClient())
{
using (HttpResponseMessage responce = await client.PostAsync(url,q))
{
using (HttpContent content = responce.Content)
{
string mycontent = await content.ReadAsStringAsync();
Console.WriteLine(mycontent);
}
}
}
}
}
}
this is console application but console writes error:
{"":["The input was not valid."]}
This is model of method
Any help?
In my opinion, key value pair is causing the problem.
The API is expecting personalIDNumber and pharmacyID as two separate parameters.
Simplest solution is to just create a class with these two properties:
public class InputFields
{
public string personalIDNumber{get;set;}
public string pharmacyId{get;set;}
}
This will work as long as your API has mode of this type as input parameter.
Please note that sending two parameters in HTTP body as post you may have to code additionally as mentioned here.
Hope this helps.
I am attempting to send a stream using RabbitMQ and Servicestack (v1.0.41 using .NET Core).
My Request implements ServiceStack.Web.IRequiresRequestStream, and the stream property is set in the client, but when it gets to the server, the stream is NULL.
Complete Repo
Server Code:
using System;
using System.IO;
using System.Threading.Tasks;
using Funq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.DependencyInjection;
using ServiceStack;
using ServiceStack.Messaging;
using ServiceStack.RabbitMq;
using ServiceStack.Web;
namespace Server
{
class Program
{
public static void Main(string[] args)
{
IWebHost host = new WebHostBuilder()
.UseServer(new RabbitServer())
.UseStartup<Startup>()
.Build();
host.Run();
}
}
public class RabbitServer : IServer
{
public void Dispose(){}
public void Start<TContext>(IHttpApplication<TContext> application){}
public IFeatureCollection Features { get; } = new FeatureCollection();
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddLogging();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseServiceStack((AppHostBase)Activator.CreateInstance<AppHost>());
app.Run((RequestDelegate)(context => (Task)Task.FromResult<int>(0)));
}
}
public class AppHost : AppHostBase
{
public AppHost()
: base("My Test Service", typeof(MyService).GetAssembly())
{
}
public override void Configure(Container container)
{
var mqServer = new RabbitMqServer("127.0.0.1");
container.Register<IMessageService>(mqServer);
mqServer.RegisterHandler<HelloRequest>(ExecuteMessage);
mqServer.Start();
}
}
public class MyService : Service
{
public HelloResponse Any(HelloRequest request)
{
Console.WriteLine($"Stream is null: {request.RequestStream == null}");
return new HelloResponse { Counter = request.Counter };
}
}
public class HelloRequest : IReturn<HelloResponse>, IRequiresRequestStream
{
public int Counter { get; set; }
public Stream RequestStream { get; set; }
}
public class HelloResponse
{
public int Counter { get; set; }
}
}
Client Code:
using ServiceStack;
using ServiceStack.Messaging;
using ServiceStack.RabbitMq;
using ServiceStack.Web;
using System;
using System.IO;
using System.Text;
namespace Client
{
class Program
{
static void Main(string[] args)
{
RabbitMqServer messageService = new RabbitMqServer("127.0.0.1");
RabbitMqQueueClient mqClient = messageService.MessageFactory.CreateMessageQueueClient() as RabbitMqQueueClient;
var responseQueueName = mqClient.GetTempQueueName();
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes("Hello World!")) { Position = 0 };
HelloRequest request = new HelloRequest { Counter = 100, RequestStream = ms }; //Counter is just some arbitary extra data
Guid messageId = Guid.NewGuid();
mqClient.Publish(QueueNames<HelloRequest>.In, new Message<HelloRequest>(request) { ReplyTo = responseQueueName, Id = messageId });
}
}
public class HelloRequest : IReturn<HelloResponse>, IRequiresRequestStream
{
public int Counter { get; set; }
public Stream RequestStream { get; set; }
}
public class HelloResponse
{
public int Counter { get; set; }
}
}
Note: I realise I could just use a byte[] in my request object, but I would quite like to make use of the provided IRequiresRequestStream interface so I can switch back to using HTTP rather than AMQP in the future.
I should also say, that I probably won't be using the RabbitMQ Client provided by servicestack, as I am writing custom logic to convert from HTTP to AMQP, so I will be building the rabbitMQ request manually - the code above just demonstrates the problem I am having in the simplest way possible.
I'm going to assume that this won't just work out of the box with AMQP (as it does with HTTP) - so I was thinking that I need to do something like serialize the stream to a byte[] and include it in the RabbitMQ message and then populate the dto which ServiceStack magically re-hydrates on the Server.
So two questions really...
1. Am I on the right track?
2. If so, how do I hook into the de-serialization code on the server so that I have access to the raw RabbitMQ message in order to convert my byte[] back to a stream and set the stream on my dto?
You can't send a IRequiresRequestStream Request DTO into a MQ because it's not a normal serialized Request DTO, instead it instructs ServiceStack to skip deserializing the Request DTO and instead inject the HTTP Request Stream so the Service can perform its own Deserialization instead, this is different to a normal Request DTO which is serialized and can be sent as the body in an MQ Message.
One option if you want to share implementation between a IRequiresRequestStream Service and a Service that can be called by MQ is to just delegate to a common Service that accepts bytes, e.g:
//Called from HTTP
public object Any(HelloStream request) =>
Any(new HelloBytes { Bytes = request.RequestStream.ReadFully() });
//Called from HTTP or MQ
public object Any(HelloBytes request)
{
//= request.Bytes
}
Hello there Stackoverflow! (first time posting here so plz be nice :P)
So, I've decided to make a discord bot 1.0 in c# (i'm learning c# atm) and I have gotten in to a problem and i'm not sure how to fix it..
So, to describe what i'm trying to do is following.
I'm trying to make it so i can have different classes for x commands such as .say etc instead of having em all in the "commands" one below so its a bit easier to work with.
I got these working three scripts but cant get the fourth to work
//Startup
using System;
using System.Threading.Tasks;
using Discord;
using Discord.WebSocket;
using Discord.Commands;
namespace MyBot
{
public class Program
{
// Convert our sync main to an async main.
public static void Main(string[] args) =>
new Program().Start().GetAwaiter().GetResult();
private DiscordSocketClient client;
private CommandHandler handler;
public async Task Start()
{
// Define the DiscordSocketClient
client = new DiscordSocketClient();
var token = "Censored";
// Login and connect to Discord.
await client.LoginAsync(TokenType.Bot, token);
await client.StartAsync();
var map = new DependencyMap();
map.Add(client);
handler = new CommandHandler();
await handler.Install(map);
// Block this program until it is closed.
await Task.Delay(-1);
}
private Task Log(LogMessage msg)
{
Console.WriteLine(msg.ToString());
return Task.CompletedTask;
}
}
}
//My command handler
using System.Threading.Tasks;
using System.Reflection;
using Discord.Commands;
using Discord.WebSocket;
namespace MyBot
{
public class CommandHandler
{
private CommandService commands;
private DiscordSocketClient client;
private IDependencyMap map;
public async Task Install(IDependencyMap _map)
{
// Create Command Service, inject it into Dependency Map
client = _map.Get<DiscordSocketClient>();
commands = new CommandService();
_map.Add(commands);
map = _map;
await commands.AddModulesAsync(Assembly.GetEntryAssembly());
client.MessageReceived += HandleCommand;
}
public async Task HandleCommand(SocketMessage parameterMessage)
{
// Don't handle the command if it is a system message
var message = parameterMessage as SocketUserMessage;
if (message == null) return;
// Mark where the prefix ends and the command begins
int argPos = 0;
// Determine if the message has a valid prefix, adjust argPos
if (!(message.HasMentionPrefix(client.CurrentUser, ref argPos) || message.HasCharPrefix('!', ref argPos))) return;
// Create a Command Context
var context = new CommandContext(client, message);
// Execute the Command, store the result
var result = await commands.ExecuteAsync(context, argPos, map);
// If the command failed, notify the user
if (!result.IsSuccess)
await message.Channel.SendMessageAsync($"**Error:** {result.ErrorReason}");
}
}
}
//Commands
using System;
using System.Linq;
using System.Threading.Tasks;
using Discord;
using Discord.Commands;
using Discord.WebSocket;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace MyBot.Modules.Public
{
public class PublicModule : ModuleBase
{
[Command("invite")]
[Summary("Returns the OAuth2 Invite URL of the bot")]
public async Task Invite()
{
var application = await Context.Client.GetApplicationInfoAsync();
await ReplyAsync(
$"A user with `MANAGE_SERVER` can invite me to your server here: <https://discordapp.com/oauth2/authorize?client_id={application.Id}&scope=bot>");
}
[Command("leave")]
[Summary("Instructs the bot to leave this Guild.")]
[RequireUserPermission(GuildPermission.ManageGuild)]
public async Task Leave()
{
if (Context.Guild == null) { await ReplyAsync("This command can only be ran in a server."); return; }
await ReplyAsync("Leaving~");
await Context.Guild.LeaveAsync();
}
}
}
//This is the one i want to work but i only get "Unknown command" as error?
using Discord.Commands;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace MyBot.Modules.Public
{
class test : ModuleBase
{
[Command("say")]
[Alias("echo")]
[Summary("Echos the provided input")]
public async Task Say([Remainder] string input)
{
await ReplyAsync(input);
}
}
}
If you know what i do wrong please tell me or reefer me to some info about the problem and i can try fix it :)
Thanks in advance!
PS, im sorry if there is a dupe of this question but i don't know what to search for to find it
EDIT
I've been told to "Pit the metohds (cmds) in the class" but how would i go around todo that?
The answer is following
Add Public before the class {name}so it would be
namespace MyBot.Modules.Public
{
**Public** class test : ModuleBase
{
[Command("say")]
[Alias("echo")]
[Summary("Echos the provided input")]
public async Task Say([Remainder] string input)
{
await ReplyAsync(input);
}
}
}