How to capture the incoming data from MSTeam? - post

I have configured a outgoing webhook in msteam which should capture the data user is passing in the api and display over console or msteam.How can it be done?
Currently i have tried this and could capure the incoming data but the same is not working in the base Controller
public async Task<Activity> gettestdata()
{
string content = await this.Request.Content.ReadAsStringAsync();
Activity incomingActivity = JsonConvert.DeserializeObject<Activity>(content);
return incomingActivity;
}
Any other method is there to do the same as in Base Controller( public class TestController : Controller) the below command is not supported,it says 'Content' cannot be found
string content = await this.Request.Content.ReadAsStringAsync();

Related

Unable to resolve service for type 'Microsoft.AspNetCore.SignalR.HubConnectionContext' while attempting to activate an api controller

I'm developing a web application with ASP.NET Core (MVC) that will display some information to a group of users. They will be authenticated using Windows Athentication. I recently started using SignalR because I want them to receive push notifications based on certain actions that are triggered from another program that is written in Python. That Python program send HTTP post requests to an API controller within the web app. However I want those notifications to be sent to specific users.
Here's my post method in the api controller:
[HttpPost]
public void Post([FromBody] Notice notice)
{
//_pushHub.Clients.All.SendAsync("ReceiveMessage", notice.Title, notice.Body);
_pushHub.Clients.User(_nuidProvider.GetUserId(_connection)).SendAsync("ReceiveMessage", notice.Title, notice.Body);
}
It receives an object of class Notice which has two fields: Title and Body.
Then I send those values by using the method SendAsync(). When I execute it for all clients, it gets sent successfully. However, since I need it to be sent to specific users, I tried following these instructions: https://learn.microsoft.com/en-us/aspnet/core/signalr/authn-and-authz?view=aspnetcore-5.0
I created this class as suggested:
namespace MyApp.Services
{
public class NameUserIdProvider : IUserIdProvider
{
public string GetUserId(HubConnectionContext connection)
{
return connection.User?.Identity?.Name;
}
}
}
Then I added this to the StartUp at ConfigureServices:
services.AddSingleton<IUserIdProvider, NameUserIdProvider>();
services.AddSignalR();
And lastly, I modified the JS file to include the sentence: options.UseDefaultCredentials = true; as suggested in the instructions:
const conn = new signalR.HubConnectionBuilder().withUrl('/pushHub', options => {
options.UseDefaultCredentials = true;
}).build();
conn.on('ReceiveMessage', (title, body) => {
const t = title.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
const b = body.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
const date = new Date().toLocaleTimeString();
const msg = date + ' ' + t + ' ' + b;
const li = document.createElement('li');
li.innerHTML = msg;
document.getElementById('msgsList').appendChild(li);
Push.create(title, {
body: body,
timeout: 9000
});
});
conn.start().catch(err => console.error(err.toString()));
The complete api controller looks like this, but I'm not sure if I'm doing it right:
namespace MyApp.Controllers.api
{
[Route("api/[controller]")]
[ApiController]
public class NoticesController : ControllerBase
{
private readonly IHubContext<PushHub> _pushHub;
private readonly IUserIdProvider _nuidProvider;
private readonly HubConnectionContext _connection;
public NoticesController(IHubContext<PushHub> pushHub, IUserIdProvider nuidProvider, HubConnectionContext connection)
{
_pushHub = pushHub;
_nuidProvider = nuidProvider;
_connection = connection;
}
// POST api/<NoticesController>
[HttpPost]
public void Post([FromBody] Notice notice)
{
//_pushHub.Clients.All.SendAsync("ReceiveMessage", notice.Title, notice.Body);
_pushHub.Clients.User(_nuidProvider.GetUserId(_connection)).SendAsync("ReceiveMessage", notice.Title, notice.Body);
}
}
}
I think I'm not passing a proper connection object to the GetUserId method.
Any advice will be completely appreciated. Thanks!

Receiving a real incoming call in Twilio's ClientQuickstart

For the time being I use a test account in Twilio, but I hope that this has no relevance regarding my question.
As my firs experimental step towards Twilio, I'm testing the client-quickstart-csharp-1.4 package on Visual Studio 2017 on Windows.
Outgoing calls work fine to my verified phone, but I have problems with incoming calls. When I make a call from a real phone to my Twilio phonenumber, then my code in VoiceController.cs doesn't run (doesn't hit any breakpoint) and I hear a voice message about that I should reconfigure something my application (but I don't understand, what). In contrast of this, when I make a call from my TwiMLApp config page, pressing the red Call button (see picture),
then my code stops at the breakpoints, and says the text I wrote in the argumet of response.Say().
My questions:
Why does the call work differently from a real phone then from my
TwiMLApp config page?
How can I achieve my code run (i.e. say the text I wrote in the code) also when I make a call from a real phone?
How Can I achieve a real, live voice dialogue between the caller phone and my computer's speaker and microphone at incoming calls (similarly to
the outgoing calls)?
Remark 1.
Both outgoing an incoming calls work fine in Agile CRM using the Twilio widget for voice calls. But for the time of my experiments I've removed this widget (and also the "Agile CRM Twilio Saga" TwiML App from Twilio), to avoid the interferences between the different applications.
Remark 2.
Perhaps I should configure something with this screen (the screenshot found here), but I don't find this page on my twilio portal.
Instead of this, I have a page like this:
But I don't know what to change here to make my program work.
It seems that this application is designed
to manage outgoing calls (to a real phone, or to an other client of this
application) and
accept calls from the web (from an another client,
or from the TwiML App setting page, seen on the first screenshot on the o.p.), but not from a real phone.
Every (outgoing or incoming) call falls into the Index() method of the VoiceController class. This method tries to find out whether a call is incoming or outgoing.
In the case of on outgoing call, the To property of the request parameter of this method is a phonenumber, while at an incoming call from the web is a string (a username), or null (when the call comes from the TwiML App setting page). This justifies the if-else structure in the original code (extended just my remarks starting with (mma))
public ActionResult Index(VoiceRequest request)
{
var callerId = ConfigurationManager.AppSettings["TwilioCallerId"];
var response = new TwilioResponse();
if (!string.IsNullOrEmpty(request.To))
{
// wrap the phone number or client name in the appropriate TwiML verb
// by checking if the number given has only digits and format symbols
if (Regex.IsMatch(request.To, "^[\\d\\+\\-\\(\\) ]+$")) //(mma) supposed to be an outgoing call
{
response.Dial(new Number(request.To), new { callerId });
}
else //(mma) a call from one client to antorher
{
response.Dial(new Client(request.To), new { callerId });
}
}
else //(mma) incoming call from the TwiML App setting page
{
response.Say("Thanks for calling!");
}
return TwiML(response);
Question 3. can be separated into the following two parts:
If at an incoming call we want to establish a real connection with a pre-specified client (say calledUser) instead of reading out the "Thanks for calling!" message, we should replace response.Say("Thanks for calling!"); by response.Dial(cl, new { request.From }); where cl = new Client(calledUser); We can put the value of calledUser into our Local.config, so we can read it from there: var calledUser = ConfigurationManager.AppSettings["calledUser"];
If we want to accept a call from a real phone, then we should recognize this situation. This is exactly when request.To == callerId( = our Twilio phononumber) , so we must split the first condition according this. The new branch will call the pre-specified user.
Putting these together, our new code in VoiceController.cs will look like this:
public ActionResult Index(VoiceRequest request)
{
var callerId = ConfigurationManager.AppSettings["TwilioCallerId"];
var calledUser = ConfigurationManager.AppSettings["calledUser"];
var response = new TwilioResponse();
if (!string.IsNullOrEmpty(request.To))
{
// wrap the phone number or client name in the appropriate TwiML verb
// by checking if the number given has only digits and format symbols
if (Regex.IsMatch(request.To, "^[\\d\\+\\-\\(\\) ]+$"))
{
if (request.To != callerId) //(mma) supposed to be an outgoing call
{
response.Dial(new Number(request.To), new { callerId });
}
else //(mma) supposed to be an incoming call from a real phone
{
var cl = new Client(calledUser);
response.Dial(cl, new { request.From });
}
}
else //(mma) a call from one client to antorher
{
response.Dial(new Client(request.To), new { request.From });
}
}
else //(mma) incoming call from the TwiML App setting page
{
var cl = new Client(calledUser);
response.Dial(cl, new { request.From });
}
return TwiML(response);
}
Of course, if we want to accept a call, then we should start a client with the pre-defined username (calledUser). In order to do this, we can introduce a new Url parameter User, put its value into TempData["User"] by the HomeController and change the var identity = Internet.UserName().AlphanumericOnly(); line in the TokenController.cs to var identity = TempData["User"] == null ? Internet.UserName().AlphanumericOnly() : TempData["User"].ToString();
So, our new HomeController and TokenController look like this:
public class HomeController : Controller
{
public ActionResult Index(string user)
{
TempData["User"] = user;
return View();
}
}
and this:
public class TokenController : Controller
{
// GET: /token
public ActionResult Index()
{
// Load Twilio configuration from Web.config
var accountSid = ConfigurationManager.AppSettings["TwilioAccountSid"];
var authToken = ConfigurationManager.AppSettings["TwilioAuthToken"];
var appSid = ConfigurationManager.AppSettings["TwilioTwimlAppSid"];
// Create a random identity for the client
var identity = TempData["User"] == null ? Internet.UserName().AlphanumericOnly() : TempData["User"].ToString();
// Create an Access Token generator
var capability = new TwilioCapability(accountSid, authToken);
capability.AllowClientOutgoing(appSid);
capability.AllowClientIncoming(identity);
var token = capability.GenerateToken();
return Json(new
{
identity,
token
}, JsonRequestBehavior.AllowGet);
}
}
And, of course, our Local.config file should contain such a line:
<add key="calledUser" value="TheNameOfThePreDefinedUser" />

URL invalid error whenever calling from twilio

I want to make an application which can make a call to other peoples using Twilio in vb.net. whenever i am passing the URL parameter it is showing me invalid URL error. I have made a service which is returning Twimil response. And i am passing this the service URL as a parameter to Twilio URL to Initiate a call.
Not Sure is it the correct way to make call from vb.net
Twilio callvar to = new PhoneNumber("+917715*****");
var from = new PhoneNumber("+1*********");
var call = CallResource.Create(to, from,
url: new Uri("demo.twilio.com/docs/voice.xml"));
service public class Service1 : IService1
{
public void GetDataJSONFormat()
{
var response = new VoiceResponse(); response.Say("Hello Shrikant");
}
}

Returning an attachment from a remote web service

Summary
I need to retrieve attachments stored in a parent app from a link in a client of a child app. The attachments are available in the parent app via a web service call -- which returns a standard FileContentResult with content type "application/octet-stream". The best way I can think is to retrieve this via a WebRequest and pass the resulting response stream to a FileStreamResult, though I have some alternatives available.
Does anyone know if, when making a WebRequest, the response stream becomes available immediately once the first part of the response is returned or is it buffered so I don't get the response until all data has been retrieved?
Are there any other options than those listed in the full question below for doing this that I'm missing? (Other than keeping the attachments in both child and parent DBs -- I really don't want to do this since then I'd need to regularly synchronize them, too).
TLDR Version
I have two related applications which communicate through a RESTful web service. The parent application maintains a collection of entities which may have attachments. For example, a Request might have an Excel spreadsheet as an attachment. The entity and its attachment are stored in the database and access to the attachment is controlled using the same logic as access to the Request. That is, you should not be able to download an attachment if you cannot view the Request.
In the child application I maintain some integration glue for the entities assigned to a particular institution -- the app is used to communicate between our Board of Regents and each Regents school. I don't want to maintain and synchronize the full entity/attachment. I only want to maintain enough information to allow me to connect to the web service in the parent app and get the details for entities that the particular instance of the child application has access to.
This works well for the entity data itself. The amount of data is small and the overhead of buffering in the child application doesn't present a signficant delay in accessing the data. If necessary, I could cache the data locally to avoid performance penalities.
My concern is the attachments. I've considered three different mechanisms for providing access to the attachment from a client of the child application.
Generate a one-time use token and associated url that allows the client to directly download the attachment from the parent application. The token generation web service call would ensure that users of the child application should have access to the attachment. The drawback to this is that you'd only be able to click on the link once in the client. Clicking again would result in an error rather than getting the attachment.
Buffer the attachment in the child app. In this scenario I would provide a controller/action to download the attachment in the child app, then call a web service method to get the attachment and have the child app send the attachment as a FileContentResult. This removes the issue of only being able to click the link once, but the attachments could be reasonably large and buffering the data in the child application could potentially double the amount of time to download the attachment and, worse, incur a significant delay before the attachment download begins.
Link in the child app, but provide the stream from the web service request directly to a FileStreamResult. This seems, to me, to be the best option as the FileStreamResult reads in chunks rather than having to have all the data available before it is sent to the client. The only drawback that I can see here is that I can no longer dispose of the WebResponse directly as the FileStreamResult won't be executed until after my action returns.
Here is what I have for the code for API wrapper code for (2) and (3):
private class ResponseModel<T> : IDisposable
{
public T Model { get; set; }
public WebResponse Response { get; set; }
private bool Disposed { get; set; }
private void Dispose( bool disposing )
{
if (!Disposed)
{
if (disposing)
{
((IDisposable)this.Response).Dispose();
}
Disposed = true;
}
}
public void Dispose()
{
Dispose( true );
}
}
private ResponseModel<T> GetAttachmentResponse<T>( long id ) where T : IDownloadModel, new()
{
var request = GetRequest( string.Format( "{0}/api/getattachment/{1}/{2}", this.BaseUrl, this.Key, id ) );
var response = request.GetResponse();
var model = (T)Activator.CreateInstance<T>();
var contentDisposition = response.Headers["Content-Disposition"];
if (!string.IsNullOrEmpty( contentDisposition ))
{
var filename = contentDisposition.Split( new[] { ';', ' ' }, StringSplitOptions.RemoveEmptyEntries )
.SingleOrDefault( s => s.StartsWith( "filename", StringComparison.OrdinalIgnoreCase ) );
if (!string.IsNullOrEmpty( filename ))
{
model.Name = filename.Split( '=' ).Skip( 1 ).FirstOrDefault();
}
}
if (string.IsNullOrEmpty( model.Name ))
{
model.Name = "untitled";
}
return new ResponseModel<T> { Model = model, Response = response };
}
public FileDownloadModel GetAttachment( long id )
{
using (var response = GetAttachmentResponse<FileDownloadModel>( id ))
{
var reader = new BinaryReader( response.Response.GetResponseStream() );
response.Model.Content = reader.ReadBytes( (int)response.Response.ContentLength );
return response.Model;
}
}
public FileStreamDownloadModel GetAttachmentStream( long id )
{
// since we're returning the stream, we can't dispose of the response when done.
var response = GetAttachmentResponse<FileStreamDownloadModel>( id );
response.Model.Stream = response.Response.GetResponseStream();
return response.Model;
}
public interface IDownloadModel
{
string ContentType { get; }
string Name { get; set; }
}
Model classes
public class FileDownloadModel : IDownloadModel
{
public byte[] Content { get; set; }
public string Name { get; set; }
public string ContentType { get { return "application/octet-stream"; } }
}
public class FileStreamDownloadModel : IDownloadModel
{
public Stream Stream { get; set; }
public string Name { get; set; }
public string ContentType { get { return "application/octet-stream"; } }
}
I would suggest a variant on Option 1 [call it Option 1(a)].
Instead of generating a one-time token, "borrow" the MVC AntiForgeryToken classes, and have your parent application return a custom token and cookie to the child app for inclusion in the form returned to the user.
If the child application may have links for multiple documents on a single page, in the request for the token information, have the child app submit a unique identifier (identifying the page request from the user) as part of the request. You can then use this identifier in generating the tokens, and you can store the identifier as part of the verification process. This will give you a multi-use token, unique for each link on the page.
Slap an expiration time on the unique identifier, and you should be good to go.

Accessing resources via Uri in Asp.net mvc

I am working on an ASP.NET MVC web application in which I have an object with a Uri property. The Uri contains a restful link to a resource in the following form:
/Repository/Dataset/5
The Dataset action of the Repository controller returns the contents of dataset 5 as Json.
How do I call this method from the Uri and interpret the response as Json from within the object?
Many thanks.
In server side action return JsonResult.
public ActionResult Dataset(int id)
{
// reository code
return Json(model);
}
client side call $.getJSON.
My opinion is that you should not call your controller from anywhere in code.In ASP.NET MVC Controller is there to accept request, take data and choose proper view to be returned back.
Maybe you should add method on repository that is returning already JSONized data, or introduce "Middle man" that can serialize data returned from repository so controller can call middle man to do the job. Then repository (or "Middle man") can be called from anywhere in code.
e.g.(used Json.NET for json serialization):
public class MiddleMan
{
IRepository repository
public MiddleMan(IRepository repository)
{
this.repository = repository;
}
public string GetJsonObjects(int id)
{
return JsonConvert.SerializeObject(repository.GetObject(id));
}
}
then controller (or anywhere in the code) can call this middle class:
public string Dataset(int id)
{
return new MiddleMan(repository).GetJsonObjects(id);
}
For the time being I'm going to implement a uri extension method something along these lines, creating a WebRequest object for the Uri.
public static string GetContent(this Uri uri)
{
var myRequest = (HttpWebRequest) WebRequest.Create(uri);
myRequest.Method = "GET";
WebResponse myResponse = myRequest.GetResponse();
var sr = new StreamReader(myResponse.GetResponseStream(), System.Text.Encoding.UTF8);
string result = sr.ReadToEnd();
sr.Close();
myResponse.Close();
return result;
}

Resources