Microsoft Custom Speech Service issue when using web socket url - microsoft-cognitive

so recently for a work project I've been playing around with speech to text models and in particular custom speech to text models. With a bit of mixing and matching examples I've managed to get a test application to talk to the normal Bing speech to text API. But when I attempt to use it with a custom speech instance only the HTTPS URL works. When I use any of the available long form web socket URLS the error An unhandled exception of type 'System.NullReferenceException' occurred in SpeechClient.dll occurs. This is a bit of a problem as that endpoint only supports 2 minutes of transcription, where as the websocket endpoint supports up to 10 minutes.
This https://learn.microsoft.com/en-us/azure/cognitive-services/custom-speech-service/customspeech-how-to-topics/cognitive-services-custom-speech-use-endpoint page here is what I'm going off of. It says that I should use a web socket url when creating the service, but that leads to the error above.
Here my test bed code for trying it out:
using System;
using Microsoft.CognitiveServices.SpeechRecognition;
using System.IO;
namespace ConsoleApp1
{
class Program
{
DataRecognitionClient dataClient;
static void Main(string[] args)
{
Program p = new Program();
p.Run(args);
}
void Run(string[] args)
{
try
{
// Works
//this.dataClient = SpeechRecognitionServiceFactory.CreateDataClient(SpeechRecognitionMode.LongDictation, "en-US", "Key");
// Works
//this.dataClient = SpeechRecognitionServiceFactory.CreateDataClient(SpeechRecognitionMode.LongDictation, "en-US",
// "Key", "Key",
// "https://Id.api.cris.ai/ws/cris/speech/recognize/continuous");
// Doesn't work
this.dataClient = SpeechRecognitionServiceFactory.CreateDataClient(SpeechRecognitionMode.LongDictation, "en-US",
"Key", "Key",
"wss://Id.api.cris.ai/ws/cris/speech/recognize/continuous");
this.dataClient.AuthenticationUri = "https://westus.api.cognitive.microsoft.com/sts/v1.0/issueToken";
this.dataClient.OnResponseReceived += this.ResponseHandler;
this.dataClient.OnConversationError += this.ErrorHandler;
this.dataClient.OnPartialResponseReceived += this.PartialHandler;
Console.WriteLine("Starting Transcription");
this.SendAudioHelper("Audio file path");
(new System.Threading.ManualResetEvent(false)).WaitOne();
} catch(Exception e)
{
Console.WriteLine(e);
}
}
private void SendAudioHelper(string wavFileName)
{
using (FileStream fileStream = new FileStream(wavFileName, FileMode.Open, FileAccess.Read))
{
// Note for wave files, we can just send data from the file right to the server.
// In the case you are not an audio file in wave format, and instead you have just
// raw data (for example audio coming over bluetooth), then before sending up any
// audio data, you must first send up an SpeechAudioFormat descriptor to describe
// the layout and format of your raw audio data via DataRecognitionClient's sendAudioFormat() method.
int bytesRead = 0;
byte[] buffer = new byte[1024];
try
{
do
{
// Get more Audio data to send into byte buffer.
bytesRead = fileStream.Read(buffer, 0, buffer.Length);
// Send of audio data to service.
this.dataClient.SendAudio(buffer, bytesRead);
}
while (bytesRead > 0);
}
finally
{
// We are done sending audio. Final recognition results will arrive in OnResponseReceived event call.
this.dataClient.EndAudio();
}
}
}
void ErrorHandler(object sender, SpeechErrorEventArgs e)
{
Console.WriteLine(e.SpeechErrorText);
}
void ResponseHandler(object sender, SpeechResponseEventArgs e)
{
if(e.PhraseResponse.RecognitionStatus == RecognitionStatus.EndOfDictation || e.PhraseResponse.RecognitionStatus == RecognitionStatus.DictationEndSilenceTimeout)
{
Console.WriteLine("Trnascription Over");
Console.ReadKey();
Environment.Exit(0);
}
for(int i = 0; i < e.PhraseResponse.Results.Length; i++)
{
Console.Write(e.PhraseResponse.Results[i].DisplayText);
}
Console.WriteLine();
}
void PartialHandler(object sender, PartialSpeechResponseEventArgs e)
{
}
}
}
Thanks in advance for any help.

so you are probably ok with using https ...
we are revisiting the SDKs right now (restructuring/reorganizing). I expect updates in the next couple of months.
Wolfgang

The new speech service SDK supports Custom Speech Service out-of-box. Please also check the samples RecognitionUsingCustomizedModelAsync() here for details.

Related

PushSharp 4.0.10.0: HTTP/2-based Apple Push Notification service (APNs)

We use PushSharp 4.0.10 to send iOS Push Notifications:
https://github.com/Redth/PushSharp
Recently we recieved this email from Apple Developer:
"If you still send push notifications with the legacy binary protocol, it's time to update to the HTTP/2-based Apple Push Notification service (APNs) provider API. You'll be able to take advantage of great features, such as authentication with a JSON Web Token, improved error messaging, and per-notification feedback.
To give you additional time to prepare, the deadline to upgrade to the APNs provider API has been extended to March 31, 2021. We recommend upgrading as soon as possible, as APNs will no longer support the legacy binary protocol after this date."
My question is: Will PushSharp 4.0.10 still work after March 31, 2021?
There is a discussion about this but the thread was closed. But there are still some suggestions on this thread that you might want to try.
The Apple Push Notification service (APNs) will no longer support the legacy binary protocol as of November 2020
https://github.com/Redth/PushSharp/issues/923
**
EDIT - 25th March 2021
The deadline is close and #Ashita Shah asked some code snippet so I hope the following can save your time.
Add the following class dotAPNSService to your project. You can customise this structure according to your needs. Also I didn't focus the best of best coding C# standards when implementing my own push notification service. You can implement LINQ, Tasks async etc. I tested this dotAPNS library and it works perfectly fine. For Android you can still use PushSharp.
Before you implement the dotAPNSService helper class, get the following from your Apple developer account. The ApnsJwtOptions values should be:
BundleId - your app’s bundle ID. Should not include specific topics (i.e. com.myapp but not com.myapp.voip).
CertFilePath - path to the .p8 certificate you have downloaded from the Developer Center.
KeyId - The 10-character Key ID you obtained from your developer account
TeamId - The 10-character Team ID you use for developing your company’s apps. Obtain this value from your developer account.
public class dotAPNSService : IDisposable
{
public event EventHandler OnTokenExpiredHandler;
private ApnsJwtOptions options = null;
public dotAPNSService()
{
options = new ApnsJwtOptions()
{
BundleId = "com.xx.xxxx",
CertFilePath = "../../certificate.p8",
KeyId = "The_Key_Id",
TeamId = "The_Team_Id"
};
}
public void SendNotifications(String[] deviceTokens, String title, String body)
{
if (deviceTokens == null || deviceTokens.Length <= 0)
{
return;
}
if (String.IsNullOrEmpty(title))
{
return;
}
if (String.IsNullOrEmpty(body))
{
return;
}
// once you've gathered all the information needed and created an options instance, it's time to call
var apns = ApnsClient.CreateUsingJwt(new HttpClient(), options);
// start the process
foreach (String deviceToken in deviceTokens)
{
var push = new ApplePush(ApplePushType.Alert)
.AddAlert(title, body)
.AddToken(deviceToken);
Send(apns, push, deviceToken);
}
}
public void SendSilentNotifications(String[] deviceTokens)
{
try
{
if (deviceTokens == null || deviceTokens.Length <= 0)
{
return;
}
// once you've gathered all the information needed and created an options instance, it's time to call
var apns = ApnsClient.CreateUsingJwt(new HttpClient(), options);
// start the process
foreach (String deviceToken in deviceTokens)
{
var push = new ApplePush(ApplePushType.Background)
.AddContentAvailable()
.AddToken(deviceToken);
Send(apns, push, deviceToken);
}
}
finally
{
}
}
private void Send(ApnsClient apns, ApplePush push, String deviceToken)
{
try
{
var response = apns.SendAsync(push);
if (response.Result.Reason == ApnsResponseReason.Success)
{
// the notification has been sent!
}
else
{
Boolean removeToken = false;
switch (response.Result.Reason)
{
case ApnsResponseReason.BadDeviceToken:
removeToken = true;
break;
case ApnsResponseReason.TooManyRequests:
break;
}
// remove the token from database?
if (removeToken)
OnTokenExpired(new ExpiredTokenEventArgs(deviceToken));
}
}
catch (TaskCanceledException)
{
// ERROR - HTTP request timed out, you can use the deviceToken to log the error
}
catch (HttpRequestException ex)
{
// ERROR - HTTP request failed, you can use the deviceToken to log the error
}
}
protected virtual void OnTokenExpired(ExpiredTokenEventArgs args)
{
try
{
EventHandler handler = OnTokenExpiredHandler;
if (handler != null)
{
ISynchronizeInvoke target = handler.Target as ISynchronizeInvoke;
if (target != null && target.InvokeRequired)
target.Invoke(handler, new object[] { this, args });
else
handler(this, args);
}
}
catch (Exception ex)
{
}
}
}
These are the namespaces of the dotAPNSService helper class:
using System;
using System.ComponentModel;
using System.Net.Http;
using System.Threading.Tasks;
using dotAPNS;
In order to use the dotAPNSService helper on your project just pull the tokens from the database and then pass them to it. For instance, to send silent notifications:
public void SendScheduledSilentNotifications()
{
try
{
IList<User> users = _accountService.GetUsers(true);
if (users != null && users.Count > 0)
{
List<String> deviceTokens = new List<String>();
foreach (User user in users)
{
if (!String.IsNullOrEmpty(user.DeviceToken))
deviceTokens.Add(user.DeviceToken);
}
if (deviceTokens.Count > 0)
{
using (dotAPNSService service = new dotAPNSService())
{
service.OnTokenExpiredHandler += new EventHandler(OnTokenExpired);
service.SendSilentNotifications(deviceTokens.ToArray());
}
}
}
}
finally
{
}
}
To remove the expired tokens from the database you can use the following:
private void OnTokenExpired(object sender, EventArgs e)
{
if (e == null)
return;
if (e.GetType() == typeof(ExpiredTokenEventArgs))
{
var args = (ExpiredTokenEventArgs)e;
User user = _accountService.GetUserByDeviceToken(args.Token);
if (user != null)
{
user.DeviceToken = String.Empty;
Boolean success = !(_accountService.SaveUser(user) == null);
if (success)
// INFO - expired device token has been removed from database
else
// INFO - something went wrong
}
}
}
You can download the source code from here:
https://github.com/alexalok/dotAPNS
The API is now sending thousands of silent notifications at one time and there are no delays, crashes etc. Hope this code snippet helps and saves your time!

How to solve the issue like app service will not be call on every time?

I am working on Microsoft band technology, in one of my current scenario as I am sending Sms in background (means even app is not open in foreground also its working like sending Sms successfully).
For that I created the appservice by taking with Windows Runtime Component as a template.
In that app service I wrote the code for how to connect to the band and how to create the tile and how to register the Events.
And also wrote the code in Button_Pressed event for sending the Sms to others.
After that I configured the app service in package. Manifest file like this below figure.
enter image description here
My issue is appservice will not be call on every time.it will be call on two or three times per day.
Is the problem in my code or issue of Microsoft health app?
using Microsoft.Band;
using Microsoft.Band.Notifications;
using Microsoft.Band.Tiles;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.ApplicationModel.AppService;
using Windows.ApplicationModel.Background;
using Windows.Foundation.Collections;
using Windows.UI.Popups;
namespace AppServiceEvents
{
public sealed class MyTileEventHandler : IBackgroundTask
{
private BackgroundTaskDeferral backgroundTaskDeferral;
private AppServiceConnection appServiceConnection;
IBandClient bandClient;
//BandTile tile;
//IEnumerable<BandTile> tiles;
//Guid tileGuid;
public void Run(IBackgroundTaskInstance taskInstance)
{
//throw new NotImplementedException();
this.backgroundTaskDeferral = taskInstance.GetDeferral(); taskInstance.Canceled += OnTaskCanceled;
//await ConnectBand();
// Add handlers for tile events
BackgroundTileEventHandler.Instance.TileOpened += EventHandler_TileOpened;
BackgroundTileEventHandler.Instance.TileClosed += EventHandler_TileClosed;
BackgroundTileEventHandler.Instance.TileButtonPressed += EventHandler_TileButtonPressed;
// Set up handler for incoming app service request messages
var details = taskInstance.TriggerDetails as AppServiceTriggerDetails;
this.appServiceConnection = details.AppServiceConnection;
this.appServiceConnection.RequestReceived +=OnRequestReceived;
}
private async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
//throw new NotImplementedException();
var messageDeferral = args.GetDeferral();
ValueSet response = new ValueSet();
ValueSet request = args.Request.Message;
// Decode the received message and call the appropriate handler
BackgroundTileEventHandler.Instance.HandleTileEvent(request);
// Send the response
await args.Request.SendResponseAsync(response);
messageDeferral.Complete();
}
private void OnTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
//throw new NotImplementedException();
DisconnectBand();
if (this.backgroundTaskDeferral != null)
{
this.backgroundTaskDeferral.Complete();
}
}
private void EventHandler_TileOpened(object sender, BandTileEventArgs<IBandTileOpenedEvent> e)
{
// TODO: Handle the tile opening
LogEvent(String.Format("EventHandler_TileOpened: TileId={0} Timestamp={1}", e.TileEvent.TileId, e.TileEvent.Timestamp));
// We create a Band connection when the tile is opened and keep it connected until the tile closes.
ConnectBand();
}
private void EventHandler_TileClosed(object sender, BandTileEventArgs<IBandTileClosedEvent> e)
{
// TODO: Handle the tile closing
LogEvent(String.Format("EventHandler_TileClosed: TileId={0} Timestamp={1}", e.TileEvent.TileId, e.TileEvent.Timestamp));
// Disconnect the Band now that the user has closed the tile.
DisconnectBand();
}
private void EventHandler_TileButtonPressed(object sender, BandTileEventArgs<IBandTileButtonPressedEvent> e)
{
// TODO: Handle the button push
LogEvent(String.Format("EventHandler_TileButtonPressed: TileId={0} PageId={1} ElementId={2}", e.TileEvent.TileId, e.TileEvent.PageId, e.TileEvent.ElementId));
// We should have a Band connection from the tile open event, but in case the OS unloaded our background code
// between that event and this button press event, we restore the connection here as needed.
ConnectBand();
var tileid = e.TileEvent.TileId;
SendMessage(tileid);
//await new MessageDialog("This is an background task"+tileid).ShowAsync();
}
private void ConnectBand()
{
if (this.bandClient == null)
{
// Note that we specify isBackground = true here to avoid conflicting with any foreground app connection to the Band
Task<IBandInfo[]> getBands = BandClientManager.Instance.GetBandsAsync(isBackground: true);
getBands.Wait();
IBandInfo[] pairedBands = getBands.Result;
if (pairedBands.Length == 0)
{
LogEvent("ERROR - No paired Band");
}
try
{
Task<IBandClient> connect = BandClientManager.Instance.ConnectAsync(pairedBands[0]);
connect.Wait();
this.bandClient = connect.Result;
}
catch
{
LogEvent("ERROR - Unable to connect to Band");
}
}
}
/// <summary>
/// If currently connected to the Band, then disconnect.
/// </summary>
private void DisconnectBand()
{
if (bandClient != null)
{
bandClient.Dispose();
bandClient = null;
}
}
const string LogFileName = "EventLog.txt";
/// <summary>
/// Log event strings to a text file
/// </summary>
/// <param name="eventString">String describing the event</param>
private void LogEvent(string eventString)
{
using (FileStream stream = new FileStream("EventLog.txt", FileMode.Append))
{
string outputString = String.Format("{0}: {1}\r\n", DateTime.Now, eventString);
byte[] outputASCII = Encoding.ASCII.GetBytes(outputString);
stream.Write(outputASCII, 0, outputASCII.Length);
}
}
private async void SendMessage(Guid tileGuid)
{
try
{ // Send a message to the Band for one of our tiles,
// and show it as a dialog.
await bandClient.NotificationManager.SendMessageAsync(tileGuid, "Task", "This is an AppService Task", DateTimeOffset.Now, MessageFlags.ShowDialog);
}
catch (BandException ex)
{
// handle a Band connection exception
}
}
}
}
Please tell me how to resolve the above issue and tell me how to debug the appservice in VS 2015 but not a background task.
Regards,
Pradeep

Live broadcast of the video site with Asp.Net WebForms + WebApi + HTML5

The problem is this:
on the server have a video file;
The administrator runs it on the play (video broadcast begins);
user is connected to the server - must be given to the video stream that is currently playing. A live webcast in real time.
To implement this task, I took as a basis for the article:
http://www.strathweb.com/2013/01/asynchronously-streaming-video-with-asp-net-web-api/
It worked. To give the stream a video file independently and in parallel.
I was looking on.
Next it was necessary to solve the problem of broadcasting to multiple customers (paragraph 3 in the job). I took this article:
http://gigi.nullneuron.net/gigilabs/streaming-data-with-asp-net-web-api-and-pushcontentstream/
Since I have to give evidence in the video byte - I replaced the StreamWriter class to Stream.
It works for one of the first client.
I made a website Asp.Net WebForms + WebApi + HTML5.
Web page - to run a video manager and viewed by users.
WebApi gives the player for <video> (HTML5) video stream.
HTML5:
<video>
<source src="http://localhost:8080/SiteVideoStreaming/api/live/?filename=nameFile" />
</video>
WebApi controllers:
//Controllers
public class LiveController : ApiController
{
private static ConcurrentBag<Stream> clients; // List of clients who need to simultaneously deliver video data
static string fileName = "";
static LiveController()
{
clients = new ConcurrentBag<Stream>();
WriteToStream(); // The first call - start to play a video file
}
[HttpGet]
public HttpResponseMessage Subscribe(string filename)
{
fileName = HostingEnvironment.MapPath("~/Videos/") + filename;
var response = Request.CreateResponse();
response.Content = new PushStreamContent((a, b, c) => { OnStreamAvailable(a, b, c); }, "video/mp4");
return response;
}
private void OnStreamAvailable(Stream stream, HttpContent content, TransportContext context)
{
clients.Add(stream); // Add new client
}
//Class record a video file into a streams
public async static void WriteToStream()
{
var buffer = new byte[65536];
using (var video = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var length = (int)video.Length;
var bytesRead = 1;
while (length > 0 && bytesRead > 0)
{
bytesRead = video.Read(buffer, 0, Math.Min(length, buffer.Length));
foreach (var client in clients)// Each client in turn we return video data
{
try
{
await client.WriteAsync(buffer, 0, bytesRead); // ERROR - here !!! when you connect a second client
await client.FlushAsync();
}
catch (Exception ex)
{
Stream ignore;
clients.TryTake(out ignore);
}
}
length -= bytesRead;
}
}
}
}
If the request first came from one client - is given to video. Working.
If the request from the second client - when you try to start to give him a stream error occurs.
In this connection drops and the first client.
The error is as follows:
[System.Web.HttpException] = {"The remote host closed the connection.
The error code is 0x800704CD."}
As I understood after a search on the Internet is:
0x800704CD "An operation was attempted on a nonexistent network
connection."
Tell me that I'm not doing right?
Thank you.
I do so.
I use this controller:
public class VideoController : ApiController
{
// GET api/<controller>
public HttpResponseMessage Get(string filename)
{
if (filename == null)
return new HttpResponseMessage(HttpStatusCode.BadRequest);
string filePath = HostingEnvironment.MapPath("~/Videos/") + filename;
if (Request.Headers.Range != null)
{
//Range Specifc request: Stream video on wanted range.
try
{
//NOTE: ETag calculation only with file name is one approach (Not the best one though - GUIDs or DateTime is may required in live applications.).
Encoder stringEncoder = Encoding.UTF8.GetEncoder();
byte[] stringBytes = new byte[stringEncoder.GetByteCount(filePath.ToCharArray(), 0, filePath.Length, true)];
stringEncoder.GetBytes(filePath.ToCharArray(), 0, filePath.Length, stringBytes, 0, true);
MD5CryptoServiceProvider MD5Enc = new MD5CryptoServiceProvider();
string hash = BitConverter.ToString(MD5Enc.ComputeHash(stringBytes)).Replace("-", string.Empty);
HttpResponseMessage partialResponse = Request.CreateResponse(HttpStatusCode.PartialContent);
partialResponse.Headers.AcceptRanges.Add("bytes");
partialResponse.Headers.ETag = new EntityTagHeaderValue("\"" + hash + "\"");
var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
partialResponse.Content = new ByteRangeStreamContent(stream, Request.Headers.Range, new MediaTypeHeaderValue("video/mp4"));
return partialResponse;
}
catch (Exception ex)
{
return new HttpResponseMessage(HttpStatusCode.InternalServerError);
}
}
else
{
return new HttpResponseMessage(HttpStatusCode.RequestedRangeNotSatisfiable);
}
}
}
On the client side - I run it <video> video player through technology SignalR.

Stream.WriteAsync throws The remote host closed the connection exception

I have an asp.net webforms application and to retrieve video from database that saved in varbinary format and show it as html5 video tag.
after a googled it, i found a way that i should play it asynchronously using ASP.Net WebApi, it works fine
First problem
When video played first time and the user click on play button to replay the video, The remote host closed the connection. The error code is 0x800704CD exception throws at line await outputStream.WriteAsync(buffer, 0, bytesRead);.
Second Problem
When user click on seek bar, the video goes to played from first.
NOTE
Internet Explorer 11 plays the video without any problem, but firefox and chrome have both problems.
how can i solve this problem?
Here is my codes:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.EnableCors();
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "VideoApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
public class VideoController : ApiController
{
public IVideoRepository videoRepository;
public HttpResponseMessage Get(long id)
{
try
{
videoRepository = new VideoRepository();
Video video = videoRepository.load(id);
if (video != null)
{
var videoStream = new VideoStream(video.fileContent);
string ext = video.extension;
var response = Request.CreateResponse();
response.Content = new PushStreamContent((Action<Stream, HttpContent, TransportContext>)videoStream.WriteToStream, new MediaTypeHeaderValue("video/" + ext));
response.Content.Headers.Add("Content-Disposition", "attachment;filename=" + video.fullName.Replace(" ", ""));
response.Content.Headers.Add("Content-Length", videoStream.FileLength.ToString());
return response;
}
else
{
return Request.CreateResponse(HttpStatusCode.NotFound);
}
}
catch (Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.ServiceUnavailable, e);
}
}
}
public class VideoStream
{
private readonly byte[] _fileContent;
private long _contentLength;
public long FileLength
{
get { return _contentLength; }
}
public VideoStream(byte[] content)
{
_contentLength = content.Length;
_fileContent = content;
}
public async void WriteToStream(Stream outputStream, HttpContent content, TransportContext context)
{
try
{
var buffer = new byte[65536];
MemoryStream memoryStream = new MemoryStream();
memoryStream.Write(_fileContent, 0, _fileContent.Length);
memoryStream.Position = 0;
using (memoryStream)
{
var length = (int)memoryStream.Length;
var bytesRead = 1;
while (length > 0 && bytesRead > 0)
{
bytesRead = memoryStream.Read(buffer, 0, Math.Min(length, buffer.Length));
await outputStream.WriteAsync(buffer, 0, bytesRead);
length -= bytesRead;
}
}
}
catch (Exception e)
{
throw e;
}
finally
{
outputStream.Close();
}
}
}
UPDATE
after this way didn't worked properly, i had to use this way, but the new way have seekbar problem, when user click on seek bar to seek to time it dosn't work in Chrome and FireFox.
ASP.NET is not very good at video streaming. Third-party video streaming solution is the best option.
There are a few video-streaming servers (like Wowza), but they require installation and you have to buy license.
Cloud streaming service is another option. I personally prefer AWS Cloudfront. They propose distribution in various globally distributed content delivery zones. It costs really cheap and you can be sure that it will survive any traffic amount (even if all your users will watch the same video simultaneously).
You might have got the answer by now. But this might help others-
My best bet is removing the Content-length from the response headers.
Content-Length tells the caller that it needs to receive this fixed length in the response.
When you click on a play button, the complete video stream is not received (i.e., the entire Content-Length is not received.) & therefore, the error.
Another approach could be using response.Headers.TransferEncodingChunked = true, which tells the caller that it will receive a response in chunks. The only catch here is you will get a 200OK even if the stream is not present.

Push Sharp Within Asp.Net Web Service

This is more of a general Asp.Net / .Net lifecycle question.
I'm looking at using PushSharp within a Asp.Net Web Service to send notifications using APNS.
Given the nature of PushSharp using a queue to async send messages and then event callbacks to notify of 'OnNotificationSent' / 'OnServiceException' etc.. how would this work within Asp.net?
The Web Service exposes a method that instantiates PushSharp, registers for the various callback events and queues Notification Messages.
The consumer calls the web service
Once The Web service method returns, does that method continue to receive the event callbacks or is it disposed and the events will not be called?
Thanks
for your help.
Not highly recommended in Asp.net, due to application pool interfering in the process (PushSharp author says notifications in the queue but not get sent). I have implemented this though in an Asp.net website and it works.
I have moved this to a Windows service since.
Global.asax.cs file:
using PushSharp;
using PushSharp.Core;
public class Global : System.Web.HttpApplication
{
private static PushBroker myPushBroker;
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
myPushBroker = new PushBroker();
myPushBroker.OnNotificationSent += NotificationSent;
myPushBroker.OnChannelException += ChannelException;
myPushBroker.OnServiceException += ServiceException;
myPushBroker.OnNotificationFailed += NotificationFailed;
myPushBroker.OnDeviceSubscriptionExpired += DeviceSubscriptionExpired;
myPushBroker.OnDeviceSubscriptionChanged += DeviceSubscriptionChanged;
myPushBroker.OnChannelCreated += ChannelCreated;
myPushBroker.OnChannelDestroyed += ChannelDestroyed;
HttpContext.Current.Application["MyPushBroker"] = myPushBroker;
}
//IMPLEMENT PUSHBROKER DELEGATES HERE
}
aspx.cs file (example Notifications.aspx.cs):
using PushSharp;
using PushSharp.Apple;
using PushSharp.Core;
public partial class Notifications : System.Web.UI.Page {
private PushBroker myPushBroker = HttpContext.Current.Application["MyPushBroker"] as PushBroker;
//SO I CAN SWITCH FROM DEVELOPMENT TO PRODUCTION EASILY I SET THIS IN THE DATABASE
private string pushCertificate = "";
private string certPass = "";
private bool isProduction = false;
protected void btnSendNotification_Click(object sender, EventArgs e)
{
bool hasError = false;
lblError.Text = "";
if (!string.IsNullOrEmpty(txtMessage.Text))
{
try
{
GetCertificate();
//GET DEVICE TOKENS TO SEND MESSAGES TO
//NOT THE BEST WAY TO SEND MESSAGES IF YOU HAVE HUNDREDS IF NOT THOUSANDS OF TOKENS. THAT'S WHY A WINDOWS SERVICE IS RECOMMENDED.
string storedProcUser = "sp_Token_GetAll";
string userTableName = "User_Table";
DataSet dsUser = new DataSet();
UserID = new Guid(ID.Text);
dsUser = srvData.GetDeviceToken(UserID, storedProcUser, userTableName, dataConn);
DataTable userTable = new DataTable();
userTable = dsUser.Tables[0];
if (userTable.Rows.Count != 0)
{
string p12FileName = Server.MapPath(pushCertificate); //SET IN THE GET CERTIFICATE
var appleCert = File.ReadAllBytes(p12FileName);
string p12Password = certPass;
//REGISTER SERVICE
myPushBroker.RegisterAppleService(new ApplePushChannelSettings(isProduction, appleCert, p12Password));
DataRow[] drDataRow;
drDataRow = userTable.Select();
string savedDeviceToken = "";
for (int i = 0; i < userTable.Rows.Count; i++)
{
if (drDataRow[i]["DeviceToken"] is DBNull == false)
{
savedDeviceToken = drDataRow[i]["DeviceToken"].ToString();
myPushBroker.QueueNotification(new AppleNotification()
.ForDeviceToken(savedDeviceToken)
.WithAlert(txtMessage.Text)
.WithBadge(1)
.WithSound("sound.caf"));
//NOTHING TO DO ANYMORE. CAPTURE IN THE PUSH NOTIFICATION DELEGATE OF GLOBAL ASCX FILE WHAT HAPPENED TO THE SENT MESSAGE.
}
}
}
}
catch(Exception ex)
{
}
finally
{
}
}
}
}
Check out EasyServices it allows you to easily push notifications to various push servers using PushSharp without having to take care of un-received notifications even when using ASP.NET
var _pushNotificationService = EngineContext.Current.Resolve<IPushNotificationService>();
_pushNotificationService.InsertNotification(NotificationType type, string title, string message, int subscriberId, PushPriority Priority = PushPriority.Normal);
https://easyservices.codeplex.com

Resources