I want to deploy a server (on Azure) using SignalR.
And the console client, so that it accepts commands from the server.
The server code was taken from here: https://learn.microsoft.com/ru-ru/aspnet/signalr/overview/getting-started/tutorial-getting-started-with-signalr
Example of a console client from here:https://www.codeproject.com/Articles/804770/Implementing-SignalR-in-Desktop-Applications
using Microsoft.AspNet.SignalR.Client;
using System;
namespace SignalRClient
{
class Program
{
static void Main(string[] args)
{
IHubProxy _hub;
string url = #"https://signalrchatmsdn20210410135946.azurewebsites.net/";
//string url = #"http://localhost:62545";
var connection = new HubConnection(url);
_hub = connection.CreateHubProxy("BetHub");
connection.Start().Wait();
_hub.On("ReceiveLength", x => Console.WriteLine(x));
string line = null;
while ((line = System.Console.ReadLine()) != null)
{
_hub.Invoke("DetermineLength", line).Wait();
}
Console.Read();
}
}
}
If I run the server locally, everything works (string url = #"http://localhost:62545";)
If I run the server on Azure, it works through the browser. But the console client throws an exception.
System.Net.WebException
jdweng absolutely right.
In my case, it was enough to change the deployment setting.
TLS\SSL settings => HTTPS Only: Off
Enabled the Cloud Vision API
Downloaded the JSON file from the google cloud.
How to connect the JSON file with the c# windows application and connect with the Google cloud vision for text read from the image?
I believe you should use something similar with the documentation :
Quickstart: Using client libraries
using Google.Cloud.Vision.V1;
using System;
namespace GoogleCloudSamples
{
public class QuickStart
{
public static void Main(string[] args)
{
// jsonPath is the path to the key.json file
var credential = GoogleCredential.FromFile(jsonPath);
// Instantiates a client
var client = ImageAnnotatorClient.Create(credential);
// Load the image file into memory
var image = Image.FromFile("wakeupcat.jpg");
// Performs label detection on the image file
var response = client.DetectLabels(image);
foreach (var annotation in response)
{
if (annotation.Description != null)
Console.WriteLine(annotation.Description);
}
}
}
}
So I want to upload video's from client desktop application to Azure Media Services (which of course uses Azure Storage).
I am trying to do a combination of:
this old documentation: 3 - Uploading Video into Microsoft Azure Media Services
and this relative new documentation: Upload multiple files with Media Services .NET SDK.
The first one shows an perfect example of my scenario, but the second one illustrates how to use BlobTransferClient to upload multiple files and have a "progress" indicator.
The problem: It does seem to upload and I don't get any error after uploading, yet nothing is showing up in Azure portal / Storage account.
It seems to upload because task takes long, task manager shows wifi upload progress and Azure storage shows that (successful) requests are being made.
So, serverside, I create a SasLocator for a temporary time:
public async Task<VideoUploadModel> GetSasLocator(string filename)
{
var assetName = filename + DateTime.UtcNow;
IAsset asset = await _context.Assets.CreateAsync(assetName, AssetCreationOptions.None, CancellationToken.None);
IAccessPolicy accessPolicy = _context.AccessPolicies.Create(assetName, TimeSpan.FromMinutes(10),
AccessPermissions.Write);
var locator = _context.Locators.CreateLocator(LocatorType.Sas, asset, accessPolicy);
var blobUri = new UriBuilder(locator.Path);
blobUri.Path += "/" + filename;
var model = new VideoUploadModel()
{
Filename = filename,
AssetName = assetName,
SasLocator = blobUri.Uri.AbsoluteUri,
AssetId = asset.Id
};
return model;
}
And client-side, I try to upload:
public async Task UploadVideoFileToBlobStorage(string[] files, string sasLocator, CancellationToken cancellationToken)
{
var blobUri = new Uri(sasLocator);
var sasCredentials = new StorageCredentials(blobUri.Query);
//var blob = new CloudBlockBlob(new Uri(blobUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped)), sasCredentials);
var blobClient = new CloudBlobClient(new Uri(blobUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped)), sasCredentials);
var blobTransferClient = new BlobTransferClient(TimeSpan.FromMinutes(1))
{
NumberOfConcurrentTransfers = 2,
ParallelTransferThreadCount = 2
};
//register events
blobTransferClient.TransferProgressChanged += BlobTransferClient_TransferProgressChanged;
//files
var uploadTasks = new List<Task>();
foreach (var filePath in files)
{
await blobTransferClient.UploadBlob(blobUri, filePath, new FileEncryption(), cancellationToken, blobClient, new NoRetry());
}
//StorageFile storageFile = null;
//if (string.IsNullOrEmpty(file.FutureAccessToken))
//{
// storageFile = await StorageFile.GetFileFromPathAsync(file.Path).AsTask(cancellationToken);
//}
//else
//{
// storageFile = await StorageApplicationPermissions.FutureAccessList.GetFileAsync(file.FutureAccessToken).AsTask(cancellationToken);
//}
//cancellationToken.ThrowIfCancellationRequested();
//await blob.UploadFromFileAsync(storageFile);
}
I know I am probably not doing it correctly with naming of assets and using the progress indicator instead of await, but of course I first want this to work first before finishing it.
I configured Azure Media Services to "Connect to Media Services API with service principal", where I created a new Azure AD app and generated keys for that, like this documentation page. I am not really sure how this exactly works, little unexperienced in Azure AD and Azure AD apps (guidance?).
Uploading:
Asset created but no files:
Storage doesn't show any files either:
Storage does show successful upload:
The reason I can't exactly follow the Upload multiple files with Media Services .NET SDK documentation is because it uses the _context (which is Microsoft.WindowsAzure.MediaServices.Client.CloudMediaContext), that _context I can use serverside but not client-side because it requires the TentantDomain,RESTAPI Endpoint, ClientId and Client Secret.
I guess uploading via SaSLocator is the correct way (?).
UPDATE 1
When uploading using CloudBlockBlob it does upload again and it is shown in my storage account within an asset, yet when I go the media services within azure and click on the particular asset, it doesn't show any files.
So the code for that:
var blob = new CloudBlockBlob(new Uri(blobUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped)), sasCredentials);
//files
var uploadTasks = new List<Task>();
foreach (var filePath in files)
{
await blob.UploadFromFileAsync(filePath, CancellationToken.None);
}
I've also tried to upload an asset manually within Azure. So Clicking on "Upload" in the Asset menu, then Encoding it. This all works fine.
UPDATE 2:
Digging deeper I came up with the following, not yet production-proof, way to make it currently work:
1. Get a Shared access signature directly from storage and upload it to there:
public static async Task<string> GetMediaSasLocator(string filename)
{
CloudBlobContainer cont = await GetMediaContainerAsync();
SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy()
{
SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddMinutes(60),
Permissions = SharedAccessBlobPermissions.Write,
SharedAccessStartTime = DateTimeOffset.UtcNow.AddMinutes(-5)
};
await cont.FetchAttributesAsync();
return cont.Uri.AbsoluteUri + "/" + filename + cont.GetSharedAccessSignature(policy);
}
With this SaS I can upload just like I showed in UPDATE 1, nothing changed there.
2. Create a Azure Function (which was already planned to do) which handles the asset creation, file uploading to asset, encoding and publishing.
This has been done by following this tutorial: Azure Functions Tools for Visual Studio and then implement the code that is illustrated in Upload multiple files with Media Services .NET SDK.
So this "works" but is not perfect yet, I still don't have my progress indicator within my client WPF application and the Azure Function takes quite a long time to complete because we basically "upload" the file again to an Asset after it is already in Azure Storage. I rather use a method to either copy from one container to an asset container.
I came to this point because Azure functions need a fixed given container name, since assets create their own containers within an storage account, you can't trigger an Azure function on those. So to work with Azure Functions it seems I really have to upload it to a fixed container name and thereafter do the rest.
Question still remains: Why uploading a video file to Azure Storage via the BlobTransferClient does not work? And if it will work, how do I trigger an Azure function based on multiple containers. A 'path' like asset-{name}/{name}.avi would be preferred.
Eventually it turned out that I need to specify the base URL in the UploadBlob method, so without the filename itself which is within the SasLocator URL, but only the container name.
Once I fixed that I also noted it didn't upload to the filename I have provided in the SasLocator I generated server side (it includes a customerID prefix). I had to use one of the other method overloads to get the correct filename.
public async Task UploadVideoFilesToBlobStorage(List<VideoUploadModel> videos, CancellationToken cancellationToken)
{
var blobTransferClient = new BlobTransferClient();
//register events
blobTransferClient.TransferProgressChanged += BlobTransferClient_TransferProgressChanged;
//files
_videoCount = _videoCountLeft = videos.Count;
foreach (var video in videos)
{
var blobUri = new Uri(video.SasLocator);
//create the sasCredentials
var sasCredentials = new StorageCredentials(blobUri.Query);
//get the URL without sasCredentials, so only path and filename.
var blobUriBaseFile = new Uri(blobUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path,
UriFormat.UriEscaped));
//get the URL without filename (needed for BlobTransferClient (seems to me like a issue)
var blobUriBase = new Uri(blobUriBaseFile.AbsoluteUri.Replace("/"+video.Filename, ""));
var blobClient = new CloudBlobClient(blobUriBaseFile, sasCredentials);
//upload using stream, other overload of UploadBlob forces to put online filename of local filename
using (FileStream fs = new FileStream(video.FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
await blobTransferClient.UploadBlob(blobUriBase, video.Filename, fs, null, cancellationToken, blobClient,
new NoRetry(), "video/x-msvideo");
}
_videoCountLeft -= 1;
}
blobTransferClient.TransferProgressChanged -= BlobTransferClient_TransferProgressChanged;
}
private void BlobTransferClient_TransferProgressChanged(object sender, BlobTransferProgressChangedEventArgs e)
{
Console.WriteLine("progress, seconds remaining:" + e.TimeRemaining.Seconds);
double bytesTransfered = e.BytesTransferred;
double bytesTotal = e.TotalBytesToTransfer;
double thisProcent = bytesTransfered / bytesTotal;
double procent = thisProcent;
//devide by video amount
int videosUploaded = _videoCount - _videoCountLeft;
if (_videoCountLeft > 0)
{
procent = (thisProcent + videosUploaded) / _videoCount;
}
procent = procent * 100;//to real %
UploadProgressChangedEvent?.Invoke((int)procent, videosUploaded, _videoCount);
}
Actually Microsoft.WindowsAzure.MediaServices.Client.BlobTransferClient should be able to do concurrent uploads but there is no Method for uploading multiple yet it has properties for NumberOfConcurrentTransfers and ParallelTransferThreadCount, not sure how to use this.
I didn't check if this is now working with Assets as well because I now upload to 1 single container for every file and later using an Azure Function to process to an Asset, mainly because I can't trigger an Azure Function on a dynamic container name (every asset creates its own container).
I'm new with Xamarin development. I am using Azure bucket for file uploading in android mobile app.
For test purpose i have build the console application that is uploading file on azure bucket successfully without any interrupt.
But when i'm trying to create access token from mobile development it get stuck and give me time out exception. If i create the token from console application and use that token for file uploading it give me another exception like" place holder not found".
As i expected i need a mobile service for token generation, If you have any idea please share your opinions with me that would be very helpful.
I'm also uploading Code that i'm using for android mobile development.
[Activity(Label = "WedAndroidApp", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
int count = 1;
//string sas = "https://supplypark.blob.core.windows.net/transaction-images?sv=2015-04-05&sr=c&sig=iJ8CZOi%2BktarlmrbZVHK7rYLdMOnKCeBjuPqjrrkGnM%3D&se=2016-06-09T14%3A21%3A49Z&sp=rwdl";
string sas_token = "https://supplypark.blob.core.windows.net/transaction-images?sv=2015-04-05&sr=c&sig=AeWe8rghAlKz77Xh%2BUM6S46AuUQzAaD2djqhaW9wdN8%3D&se=2016-06-09T14%3A21%3A49Z&sp=rwdl";
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
// Get our button from the layout resource,
// and attach an event to it
Button button = FindViewById<Button>(Resource.Id.MyButton);
//button.Click += delegate { button.Text = string.Format("{0} clicks!", count++); };
button.Click += async delegate {
button.Text = string.Format("{0} clicks!", count++);
await UseContainerSAS(sas_token);
};
}
static async Task UseContainerSAS(string sas)
{
//Try performing container operations with the SAS provided.
//Return a reference to the container using the SAS URI.
CloudBlobContainer container = new CloudBlobContainer(new Uri(sas));
string date = DateTime.Now.ToString();
try
{
//Write operation: write a new blob to the container.
CloudBlockBlob blob = container.GetBlockBlobReference("tdi" + date + ".txt");
string blobContent = "This blob was created with a shared access signature granting write permissions to the container. ";
MemoryStream msWrite = new
MemoryStream(Encoding.UTF8.GetBytes(blobContent));
msWrite.Position = 0;
using (msWrite)
{
await blob.UploadFromStreamAsync(msWrite);
}
Console.WriteLine("Write operation succeeded for SAS " + sas);
Console.WriteLine();
}
catch (Exception e)
{
Console.WriteLine("Write operation failed for SAS " + sas);
Console.WriteLine("Additional error information: " + e.Message);
Console.WriteLine();
}
}
}
If you're already using Azure Mobile Apps, I would recommend that you use the built-in feature that accesses Azure Storage: Connect to Azure Storage in your Xamarin.Forms app
Otherwise, you should write code that creates a SAS token on your server, not your client. The storage master key should never be distributed with your client app, as it would be a big security risk. You should have the key in your server only, and it should send a SAS token to clients to scope access to a particular blob or container.
If you're using a .NET backend Mobile App/Mobile Service, then you should just move your SAS code to a custom API on the server. If you're using Node.js, you can follow this tutorial: Work with shared access signatures in Node.js.
If you don't have a Mobile App backend, then you can use Azure Functions to generate SAS tokens. Here is a sample: https://github.com/lindydonna/GetSasToken-function.
Note that Azure Mobile Service is deprecated, so you should be using Azure Mobile Apps instead.
I am looking to create a simple webpage using C# Windows Forms Application, or a C# Console application.
Running the application will begin hosting a web page at:
http://localhost:3070/somepage
I have read a little bit on MSDN about using endpoints, however being self-taught, this isn't making a ton of sense to me...
In short, this program, when running will display some text on a webpage at localhost:3070.
Sorry for such a vague question, however my hour(s) of searching for a decent tutorial haven't yielded any understandable results...
Thanks for your time!
🛑 2020 Update:
Original answer at the bottom.
Kestrel and Katana are now a thing and I would strongly recommend you look into those things as well as OWIN
Original Answer:
You will want to look into creating an HttpListener, you can add prefixes to the listener such as Listener.Prefixes.Add("http://+:3070/") which will bind it to the port your wanting.
A simple console app: Counting the requests made
using System;
using System.Net;
using System.Text;
namespace TestServer
{
class ServerMain
{
// To enable this so that it can be run in a non-administrator account:
// Open an Administrator command prompt.
// netsh http add urlacl http://+:8008/ user=Everyone listen=true
const string Prefix = "http://+:3070/";
static HttpListener Listener = null;
static int RequestNumber = 0;
static readonly DateTime StartupDate = DateTime.UtcNow;
static void Main(string[] args)
{
if (!HttpListener.IsSupported)
{
Console.WriteLine("HttpListener is not supported on this platform.");
return;
}
using (Listener = new HttpListener())
{
Listener.Prefixes.Add(Prefix);
Listener.Start();
// Begin waiting for requests.
Listener.BeginGetContext(GetContextCallback, null);
Console.WriteLine("Listening. Press Enter to stop.");
Console.ReadLine();
Listener.Stop();
}
}
static void GetContextCallback(IAsyncResult ar)
{
int req = ++RequestNumber;
// Get the context
var context = Listener.EndGetContext(ar);
// listen for the next request
Listener.BeginGetContext(GetContextCallback, null);
// get the request
var NowTime = DateTime.UtcNow;
Console.WriteLine("{0}: {1}", NowTime.ToString("R"), context.Request.RawUrl);
var responseString = string.Format("<html><body>Your request, \"{0}\", was received at {1}.<br/>It is request #{2:N0} since {3}.",
context.Request.RawUrl, NowTime.ToString("R"), req, StartupDate.ToString("R"));
byte[] buffer = Encoding.UTF8.GetBytes(responseString);
// and send it
var response = context.Response;
response.ContentType = "text/html";
response.ContentLength64 = buffer.Length;
response.StatusCode = 200;
response.OutputStream.Write(buffer, 0, buffer.Length);
response.OutputStream.Close();
}
}
}
And for extra credit, try adding it to the services on your computer!
Microsoft Relased an Open Source Project called OWIN it is simlar to Node but bottom line it allows you to host web applications in a console application:
You can find more information here:
https://github.com/duovia/duovia-http
http://owin.org/
http://katanaproject.codeplex.com/
But if you insist in creating your personal listener you can find some help here:
http://msdn.microsoft.com/en-us/library/system.net.httplistener(VS.80).aspx
http://social.msdn.microsoft.com/Forums/vstudio/en-US/b7f476d1-3147-4b18-ba5e-0b3ce8f8a918/want-to-make-a-webserver-with-httplistener