Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
I am mainly a low level system developer so I am kind of lost with all those high level tools that Azure offers and all those buzz words.
So here's what I am trying to build: I am building a server that has a processing part (probably using Azure Batch) and a storage part (using storage, duh, and DBs). I would like to hide all of this behind an interface where client applications could:
Log in the users
Upload/Download selected files
Manage their currently running jobs or start some new ones
The client application might be on an iPad,Web browser, PC, ect... New features might arise or change on the server side. This is why would opt for a "server interface" to standardize all clients interactions, but i do not know what Azure tool would fit my needs for this interface. I am not looking for something low level as in building my own protocol and server, just something that would get the job done simply.
Cheers
Léon Cantin
Azure Mobile Services might be a good fit here. The upside is that you can prototype it quickly. In the current portal you can use Mobile Services with either a Node/JavaScript backend or an ASP.NET WebAPI backend. The node option is the fastest/easiest to implement. Some benefits of this approach:
The mobile service automatically gets created with a NoSQL-style table (thought it's actually stored in SQL Azure DB under the hood) and exposes REST endpoints for CRUD, along with customizable scripts in JS for each endpoint.
Mobile Services has native SDKs for Windows (C# or WinJS), iOS (Obj-C or Swift), Android (Java), and HTML5 (JavaScript) so you can easily connect any of your client apps to it.
The mobile service also supports background jobs written in JavaScript. This could be used for your background "processing part", though it's hard to evaluate without more details on what you want to do.
You also get built-in support for authentication (Twitter, FB, Google, MSA and AD) + push notifications (WNS, GCM, APNS, etc.)
In the new preview portal, mobile services are replaced by App Services (which includes mobile) but the node backend is not supported yet, hence my recommendation to use Mobile Services instead. You get more control with the ASP.NET WebAPI backend, but you also have to code more of the backend yourself. The advantage is that you can store your data anywhere (storage tables, DocumentDB, SQL DB, etc.)
For the file upload/download, you'd have to use Azure storage blobs, and if your mobile service needs to catalog the files associated to each user, you can simply save the full blob "path" for each file in the Mobile Service table.
The docs for Azure Mobile Services - along with many tutorials - are at http://azure.microsoft.com/en-us/documentation/services/mobile-services/. I also have 3 GitHub repos with sample code for Windows, iOS and Android that integrates with Mobile Services at https://github.com/search?q=user%3AActiveNick+AzureChatr, and a blog post that explains them at http://www.ageofmobility.com/2014/10/06/azurechatr-building-a-cross-platform-chat-app-for-windows-ios-android/.
I hope this helps.
Nick
I ended opting for a Web API which let me "call" functions from the server trough the HTTP protocole. the URL is the "name" of the function and the data are either serialized in body or in the URL. Really simple and flexible, it should work out of the box on any framework that can use HTTP or i might be able to find a library that lets me do it.
My Test code looks like this :
Client:
private async Task SubmitJob()
{
JobModel job = new JobModel { ID = 42, name = "HelloJob", completion = 100.0f };
try
{
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.PostAsJsonAsync<JobModel>("http://localhost:53122/Jobs/Submit", job);
if (response.IsSuccessStatusCode)
lblSuccess.Text = "Success!";
else
lblSuccess.Text = "Failure!";
}
catch (Exception ex)
{
string s = ex.ToString();
}
}
private async Task GetJobs()
{
try
{
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("http://localhost:53122/Jobs/Info");
if (response.IsSuccessStatusCode)
{
List<JobModel> jobList = await response.Content.ReadAsAsync<List<JobModel>>();
txtConsole.Text = "";
foreach(var job in jobList)
{
string line = "ID: " + job.ID + " Name: " + job.name + " completion: " + job.completion + "\r\n";
txtConsole.Text += line;
}
}
else
{
txtConsole.Text = "Failure!";
}
}
catch (Exception ex)
{
string s = ex.ToString();
}
}
Server:
public async Task<IHttpActionResult> GetJobInfo(int jobId)
{
try
{
JobModel a = new JobModel { name = "jobA", ID = 102, completion = 100.0f };
JobModel b = new JobModel { name = "jobB", ID = 104, completion = 42.0f };
JobModel c = new JobModel { name = "jobC", ID = 106, completion = 0.0f };
List<JobModel> result = new List<JobModel> { a, b, c };
return Ok(result);
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
[HttpPost]
public async Task<IHttpActionResult> SubmitJob([FromBody] JobModel submitedJob)
{
return Ok();
}
Related
I am building a simple restaurant management system in WPF. I have my backend in Laravel. I needed to setup a web socket to get real-time notifications on WPF app when a customer places an order from mobile app. I configured the web socket in Laravel using beyondcode/laravel-websockets. For ease, I tested the web socket on client side using laravel-echo with Vue. Everything works well there but I couldn't find any solution to replicate laravel-echo in C#.
Here is the code I am using in Vue.js with laravel-echo:
import Echo from "laravel-echo";
import Pusher from "pusher-js";
window.Pusher = Pusher;
const token = "1|CSaob3KZhU5UHiocBjPgzpazbceUKTLRLJO0ZIV0"
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'laravel_rdb',
wsHost: '127.0.0.1',
authEndpoint: 'http://localhost/may-app/public/broadcasting/auth',
encrypted: false,
forceTLS: false,
wsPort: 6001,
wssPort: 6001,
disableStats: true,
enabledTransports: ['ws', 'wss'],
auth : {
headers : {
Authorization: "Bearer " + token,
Accept: "application/json",
}
},
})
window.Echo.private('customer-order')
.listen('OrderPlaced', (e) => {
console.log(e)
})
I found SocketIOClient is used to implement web socket functionality in .NET. I tried to use a solution I found here but it didn't work for me. Also, I didn't find any way to set up my authentication URL in this package. I read socket.io documentation for anything related to authentication but I couldn't find any.
How do I implement equivalent functionality in C# .NET as in laravel-echo?
There is probably no client like laravel-echo for .NET. However, you will be able to connect to your sockets using pusher client: pusher/pusher-websocket-dotnet and this is probably the highest level of compatibility you can reach. But you will need to parse your messages and subscribe to the channels by yourself, there will be no sweet wrapping like in laravel-echo =(
I was able to implement a solution using the package mentioned by PunyFlash in the answers. The NuGet package is available here and here is the GitHub repo.
My solution might be useful for someone in the future so, my equivalent code for the laravel-echo code above, in .NET is:
internal class OrderSocket
{
public static async void Connect()
{
try
{
//Setting authentication
var authorizer = new CustomAuthorizer("http://localhost/may-app/public/broadcasting/auth")
{
AuthenticationHeader = new System.Net.Http.Headers.AuthenticationHeaderValue("Authorization", "Bearer " + "1|CSaob3KZhU5UHiocBjPgzpazbceUKTLRLJO0ZIV0"),
};
//Creating pusher object with authentication
Pusher pusher = new Pusher("laravel_rdb", new PusherOptions
{
Authorizer = authorizer,
Host = "127.0.0.1:6001",
});
//Connecting to web socket
await pusher.ConnectAsync().ConfigureAwait(false);
//Subscribing to channel
Channel channel = await pusher.SubscribeAsync("private-customer-order").ConfigureAwait(false);
if (channel.IsSubscribed)
{
//Binding to an event
channel.Bind("App\\Events\\OrderPlaced", (PusherEvent eventResponse) =>
{
// Deserialize json if server returns json values
Debug.WriteLine(eventResponse.Data);
});
}
}
catch (Exception)
{
Debug.WriteLine("An exception occurred.");
}
}
}
//HttpAuthorizer child class to set default headers
internal class CustomAuthorizer : HttpAuthorizer
{
public CustomAuthorizer(string authEndpoint) : base(authEndpoint) { }
public override void PreAuthorize(HttpClient httpClient)
{
base.PreAuthorize(httpClient);
httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
}
}
I am currently working out the Microsoft Graph tutorial with C# .Net Core, and in the process I came across the following C#-method for Subscription:
[HttpGet]
public async Task<ActionResult<string>> Get()
{
var graphServiceClient = GetGraphClient();
var sub = new Microsoft.Graph.Subscription();
sub.ChangeType = "updated";
sub.NotificationUrl = config.Ngrok + "/api/notifications";
sub.Resource = "/users";
sub.ExpirationDateTime = DateTime.UtcNow.AddMinutes(15);
sub.ClientState = "SecretClientState";
var newSubscription = await graphServiceClient
.Subscriptions
.Request()
.AddAsync(sub);
Subscriptions[newSubscription.Id] = newSubscription;
if (subscriptionTimer == null)
{
subscriptionTimer = new Timer(CheckSubscriptions, null, 5000, 15000);
}
return $"Subscribed. Id: {newSubscription.Id}, Expiration: {newSubscription.ExpirationDateTime}";
}
and wanted to know how I can change it for sharepoint lists instead of users.
If I change it to /sites/{site-id} or similar it does not work. (see sub.Resource)
Github-Link: MS Repo
Microsoft Graph API uses a webhook mechanism to deliver change notifications to clients. Using the Microsoft Graph API, an app can subscribe to changes for list under a SharePoint site.
Resource Path - Changes to content within the list:
/sites/{id}/lists/{id}
For details round how to subscribe to and handle incoming notifications, see Set up notifications for changes in user data
Also make sure you check necessary permissions needed here.
I found the solution myself with the sub.Resource: /sites/{site-id}/lists/{list-id}
This question already has answers here:
How to delete a file after it was streamed in ASP.NET Core
(5 answers)
Closed 2 years ago.
I am working on an ASP.NET Core 2.1 API project, which will be consumed by an Angular App, and later on a mobile app. one of the required functionality is to zip and download a collection of files, the result zipped file is going to be large (1GB or more).
the code I have now is working as follows:
the Angular app requests the API and expects a blob response.
the API on the server creates a Zip file and reads it using memory stream.
the API returns the memory stream using File response.
the method that subscribes to the download service in Angular saves
the file.
what is happening now is when I click in the browser on the download button I have to wait for the download to be finished then the browser shows the default popup that allows the user to save and select where to save.
I was wondering if what I'm doing is correct and won't cause any memory problems in the future?
is there a better methodology where the file could be streamed smoothly, so when the download starts the browser directly shows the save message and shows the default browser progress bar?
angular code:
component click function:
download(event,id){
event.stopPropagation();
event.preventDefault();
this.myservice.Downloadservice(avatar_id).subscribe((res: any) => {
saveAs(res.data, res.filename);
});
}
service code:
DownloadAllservice(id): Observable<any> {
let authToken = localStorage.getItem('auth_token');
let _options = { headers: new Headers({ 'Authorization': `Bearer ${authToken}`, } ),responseType: ResponseContentType.Blob };
let formData = new FormData();
let options ={
type: "zip",
id: id
};
formData.append('options',JSON.stringify(options));
return this.http.post(this.baseUrl + "/api/Download/", formData, _options)
.map(response =>{
return {
'filename': this.getFileNameFromHttpResponse(response),
'data': response.blob()
} })
.catch(this.handleError);
}
.net core code:
[Authorize(Policy = "Admin")]
[DisableRequestSizeLimit]
[HttpPost("Download", Name = "Download")]
public async Task<IActionResult> Download()
{
// get files list then start creating the temp folder and zipped folder
var archive = Path.Combine(Directory.GetDirectoryRoot("wwwroot"), #"home\" + FilePath + #"\temp\" + "filename");
var temp = Path.Combine(Directory.GetDirectoryRoot("wwwroot"), #"home\" + FilePath + #"\temp");
if (!System.IO.Directory.Exists(temp))
{
Directory.CreateDirectory(temp);
}
Directory.CreateDirectory(archive);
try
{
foreach (var file_id in filelist)
{
var path = file.path;
if (!System.IO.File.Exists(Path.Combine(archive, Path.GetFileName(path)))) {
System.IO.File.Copy(path, Path.Combine(archive, Path.GetFileName(path)));
}
}
var archivezip = Path.Combine(Directory.GetDirectoryRoot("wwwroot"), #"home\" + FilePath + #"\temp\" + "filename" + ".zip");
// create a new archive
ZipFile.CreateFromDirectory(archive, archivezip);
var memory = new MemoryStream();
using (var stream = new FileStream(archivezip, FileMode.Open))
{
await stream.CopyToAsync(memory);
}
memory.Position = 0;
Directory.EnumerateFiles(archive).ToList().ForEach(f => System.IO.File.Delete(f));
Directory.EnumerateDirectories(archive).ToList().ForEach(f => System.IO.Directory.Delete(f, true));
Directory.Delete(archive);
System.IO.File.Delete(archivezip);
return File(memory, "application/octet-stream","filename.zip");
}
catch (Exception ex)
{
return new BadRequestObjectResult(ex.Message);
}
}
please note that in the future not only angular app will use the API, but mobile apps will also be added
I do a similar thing (I guess everyone does because that's apparently how it's done with Angular). I just do a basic unlimited loading spinner because, so far, I haven't needed to worry about tracking the progress.
However, there are various guides to handling this out there for you to follow.
It seems to boil down to changing your request from a simple, standard get/post request to one that listens to the events of the response.
From the linked article:
this.http.get(url, {
reportProgress: true,
observe: 'events',
responseType: 'blob'
})
Important parts there are to ensure it wants progress reports and to observe events. Once the request is observing events, then you need to handle observing them (obviously).
That, however, is a longer more involved part of the article. Go forth and good luck.
Edit: Ah, the issue is actually API side you're worried about. Fair enough, there are a variety of similar questions that might be of use then.
For the Microsoft Bot framework chatbot application that I am working on, I have configured the "Bot Channel Registration" and have hosted it on Azure.
One of the scenarios expects the user to record a video on skype and send it as an answer. I have an Azure function that saves the recorded video from skype to the Azure Storage account.
The issue I am encountering is, When I record a video on skype ()via Video Messaging option.
To gain access to the uploaded video from skype, I am providing appropriate bearer token along with the above mentioned URL but failing to get access to it.
Though the file that is uploaded from skype to the Queue (Azure function Queue triggers), the accessibility to this file is denied.
Assuming the latest patches would help, I updated all the references to .NET core 3.0.1 as of today. Looking forward to the desired approach to resolve this.
Note: This issue is only happening in "Skype for Desktop" version.
Below is the code block for your reference.
private static async Task<HttpResponseMessage> RequestFile(string contentUrl, ILogger logger, string serviceUrl)
{
var credentials = DIContainer.Instance.GetService<MicrosoftAppCredentials>();
var token = await credentials.GetTokenAsync();
using (var connectorClient = new ConnectorClient(new Uri(serviceUrl), credentials.MicrosoftAppId, credentials.MicrosoftAppPassword))
{
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream"));
var test = await httpClient.GetAsync(uri, HttpCompletionOption.ResponseContentRead);
return test;
}
}
}
Adding more code snippets:
private async Task<(string, string)> TrySaveAndGetContentUrl(IMessageActivity activity, string user)
{
var attachments = activity.Attachments;
if (attachments?.Any() ?? false)
{
var video = attachments.First();
return (await _attachmentsService.Save(video, user), video.ContentUrl);
}
return (null, null);
}
///_attachmentsService.Save method implementation
public async Task<string> Save(Attachment attachment, string user)
{
_logger.LogInformation("Enqueue save command. {#Attachment}", attachment);
var blobName = $"{user}/{Guid.NewGuid().ToString()}-{attachment.Name}";
var blob = _cloudBlobContainer.GetBlockBlobReference(blobName);
await EnqueueSaveCommand(attachment.ContentUrl, blobName, user);
return blob.Uri.ToString();
}
Please refer the below code block to save the attachments to Azure blob.
private async Task EnqueueSaveCommand(string contentUrl, string blobName, string user)
{
var queue = _queueClient.GetQueueReference(RouteNames.MediaAttachmentQueue); //RouteNames.MediaAttachmentQueue is "media-attachment-queue"
await queue.CreateIfNotExistsAsync();
var serializedMessage = JsonConvert.SerializeObject(new SaveMediaAttachmentCommand
{
FromUrl = contentUrl,
AttachmentName = blobName,
UserName = "userid#gmail.com",
});
var queueMessage = new CloudQueueMessage(serializedMessage);
await queue.AddMessageAsync(queueMessage);
}
Please suggest.
The Skype channel configuration contains the following message:
As of October 31, 2019 the Skype channel no longer accepts new Bot publishing requests. This means that you can continue to develop bots using the Skype channel, but your bot will be limited to 100 users. You will not be able to publish your bot to a larger audience. Current Skype bots will continue to run uninterrupted. Learn more
Many Skype features have been deprecated. If it was ever possible to send a video to a bot over Skype, it may not be possible any longer. It's recommended that you switch to other channels like Direct Line and Microsoft Teams.
I am currently working on a C# Windows Form project that requires the user to pay prior to any processing taking place. I am using the Square .Net SDK for payment processing and have successfully managed to get a payment through to the sandbox environment using the Checkout URL generated by the Checkout API. My question is whether there is a simple way to get whether the payment process has been completed. Right now, I am just polling the API with the same order (with identical idempotency keys) and waiting for it to return an error that the order is no longer valid. Here is the backbone of my current code:
var bodyOrderLineItems = new List<CreateOrderRequestLineItem>();
long totalCost = 100;
var charge0 = new Money.Builder().Amount(totalCost).Currency("USD").Build();
bodyOrderLineItems.Add(new CreateOrderRequestLineItem.Builder("1").Name("Incredibly Valuable Product").BasePriceMoney(charge0).Build());
var order = new CreateOrderRequest.Builder()
.ReferenceId("reference_id")
.LineItems(bodyOrderLineItems)
.Build();
var body = new CreateCheckoutRequest.Builder("Test_iKey4", order)
.AskForShippingAddress(false)
.Build();
var checkoutApi = client.CheckoutApi;
try
{
CreateCheckoutResponse result = checkoutApi.CreateCheckout(locationsString, body);
System.Diagnostics.Process.Start(result.Checkout.CheckoutPageUrl);
while (true)
{
System.Threading.Thread.Sleep(5000);
//while payment hasn't gone through
try
{
result = checkoutApi.CreateCheckout(locationsString, body);
}
catch (ApiException e)
{
MessageBox.Show(e.Errors[0].Detail);
break;
}
}
MessageBox.Show("Payment Must Have Gone Through");
}
catch (ApiException e) { MessageBox.Show(e.Errors[0].Detail); };
Is this a valid approach? While this does seem to work, I feel like I am flooding the api with requests. I am pretty inexperienced with the Square API, so any help would be appreciated.
Typically the Checkout API is used within a website, as it includes a parameter redirect_url so that when the payment is complete, the user is redirected back to your side and it includes url parameters such as the transaction id. If you don't have a website, you can instead sign up for webhooks. The PAYMENT_UPDATED webhook will be sent out when a payment has been processed, so you do not need to do polling; just listen for the webhook.