SqlDependency not firing - sql

I am trying SqlDepenedency for the first time. I am not getting any notifications on Database Update.
I am placing breakpoints inside :
OnChange(object sender, SqlNotificationEventArgs e),
but it never gets hit.
Here is my code :
protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = "Cache Refresh: " + DateTime.Now.ToLongTimeString();
DateTime.Now.ToLongTimeString();
// Create a dependency connection to the database.
SqlDependency.Start(GetConnectionString());
using (SqlConnection connection = new SqlConnection(GetConnectionString()))
{
using (SqlCommand command = new SqlCommand(GetSQL(), connection))
{
SqlDependency dependency =
new SqlDependency(command);
// Refresh the cache after the number of minutes
// listed below if a change does not occur.
// This value could be stored in a configuration file.
connection.Open();
dgHomeRequests.DataSource = command.ExecuteReader();
dgHomeRequests.DataBind();
}
}
}
private string GetConnectionString()
{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
//return "Data Source=(local);Integrated Security=true;" +"Initial Catalog=AdventureWorks;";
return ConfigurationManager.ConnectionStrings["TestData"].ConnectionString;
}
private string GetSQL()
{
return "Select [Address] From [UserAccount1]";
}
void OnChange(object sender, SqlNotificationEventArgs e)
{
// have breakpoint here:
SqlDependency dependency = sender as SqlDependency;
// Notices are only a one shot deal
// so remove the existing one so a new
// one can be added
dependency.OnChange -= OnChange;
// Fire the event
/* if (OnNewMessage != null)
{
OnNewMessage();
}*/
}
I have also placed some code in Global.asax file :
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
SqlDependency.Start(ConfigurationManager.ConnectionStrings["TestData"].ConnectionString);
}
protected void Application_End()
{
// Shut down SignalR Dependencies
SqlDependency.Stop(ConfigurationManager.ConnectionStrings["TestData"].ConnectionString);
}
}
The SQL server is on local machine. I am running the code through Visual Studio(IIS Express).
To enable service broker on database:
ALTER DATABASE SET ENABLE_BROKER
GO
To subscribe query notification, we need to give permission to IIS service account
GRANT SUBSCRIBE QUERY NOTIFICATIONS TO “<serviceAccount>”
I guessed the 2nd point is not needed as it is local. But I tried giving it some permissions. Don't know if they are right as I don't think it is using app pool.And don't need the permission on local env. if I am the user myself and created the schema myself.
One of the questions that I saw was granting :
alter authorization on database::<dbName> to [sa];
I gave that permission too.

I was missing :
dependency.OnChange += new OnChangeEventHandler(OnChange);
The new code would look like :
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(OnChange);
now I can fire
void OnChange(object sender, SqlNotificationEventArgs e)

Related

Sql Dependency - Notification received before processing current request

I am currently using sql dependency notification to detect changes in a table and process them. I am having a problem where the notification gets called while its still in the middle of completing the first request which causes duplicate processing
private void ProcessData()
{
try
{
m_Guids = new List<Guid>();
using (SqlCommand command = new SqlCommand("SP_XXX_SELECT", m_sqlConn))
{
command.CommandType = CommandType.StoredProcedure;
command.Notification = null;
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(OnDependencyChange);
SqlDependency.Start(m_ConnectionString, m_QueueName);
if (m_sqlConn.State == ConnectionState.Closed)
{
m_sqlConn.Open();
}
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
m_Guids.Add(reader.GetGuid(0));
}
}
}
Console.WriteLine(m_Guids.Count.ToString());
ProcessGuids();
}
}
}
catch (Exception ex)
{
//SendFailureEmail
}
}
private void OnDependencyChange(object sender, SqlNotificationEventArgs e)
{
SqlDependency dependency = sender as SqlDependency;
dependency.OnChange -= OnDependencyChange;
ProcessData();
}
public void OnStart()
{
SqlDependency.Stop(m_ConnectionString, m_QueueName);
SqlDependency.Start(m_ConnectionString, m_QueueName);
m_sqlConn = new SqlConnection(m_ConnectionString);
}
ProcessData method gets called again while its still in the middle of processing (processGuids) Should I subscribe to the event after processing all the data?
If I don't subscribe until processing is complete, what happens to the data that was changed during the process, which I believe doesn't get notified until next change happens?. What is the correct way of doing this or am I doing something wrong.
Thanks
SqlDependency.OnChange is called not only on data change.
In the OnDependencyChange you must check e.Type/e.Source/e.Info.
F.e., combination of {Type = Subscribe, Source = Statement, Info = Invalid} means "Statement not ready for notification, no notification started".
See Creating a Query for Notification for SQL statement requirements for notification. You must follow these requirements in SELECT statements in your SP.
Additional requirements for stored procedures are not well documented. Known restrictions for SP:
Use of SET NOCOUNT (ON and OFF) is prohibited.
Use of RETURN is prohibited.

Duplicated output from process.OutputDataReceived

I'm having an issue with duplicated content from redirected output.
In my forms I have two buttons: Run and Clear.
public partial class BatchRun : Form
{
Process process = new Process();
public BatchRun()
{
InitializeComponent();
}
private void RunBTN_Click(object sender, EventArgs e)
{
//initiate the process
this.process.StartInfo.FileName = sMasterBATname;
this.process.StartInfo.UseShellExecute = false;
this.process.StartInfo.CreateNoWindow = true;
this.process.StartInfo.RedirectStandardOutput = true;
this.process.OutputDataReceived += new DataReceivedEventHandler(StandardOutputHandler);
this.process.StartInfo.RedirectStandardInput = true;
this.process.Start();
this.process.BeginOutputReadLine();
}
public void StandardOutputHandler(object sender, DataReceivedEventArgs outLine)
{
BeginInvoke(new MethodInvoker(() =>
{
Label TestLBL = new Label();
TestLBL.Text = text.TrimStart();
TestLBL.AutoSize = true;
TestLBL.Location = new Point(10, CMDpanel.AutoScrollPosition.Y + CMDpanel.Controls.Count * 20);
CMDpanel.Controls.Add(TestLBL);
CMDpanel.AutoScrollPosition = new Point(10, CMDpanel.Controls.Count * 20);
}));
}
private void ClearBTN_Click(object sender, EventArgs e)
{
CMDpanel.Controls.Clear();
this.process.CancelOutputRead();
this.process.Close();
this.process.Refresh();
}
}
This works great if I want to run process only once i.e. close the forms once process has completed.
However, I need to allow user to rerun the same process or run a new one hence I have added a clear button the clear various controls etc.
The problem I'm having is that after clicking clear button, I want to click run button again without closing which should then run the sMAsterBAT file(CMD).
StandardOutputHandler seems to be including content of the previous run as well as the new one resulting in duplicated labels in my CMDpanel.
Is this stored in some kind of buffer? If so, How do i clear it to allow me a rerun?
Could someone explain why this is happening and how to resolve it please.
Spoke to someone at work who fixed it for me. So easy lol
private void ClearBTN_Click(object sender, EventArgs e)
{
CMDpanel.Controls.Clear();
this.process.CancelOutputRead();
this.process.Close();
this.process.Refresh();
this.process = new Process(); // this line resolved my issue!!
}
}

UCMA 3.0 - Recording an incoming call

I am new to UCMA and I am learning as I go through examples. I am trying to build 2 Lync clients A and B with the scenario as follows,
A calls B
B answers
A plays audio
B records it using Recorder.
I am stuck at trying to record the call at B. For B its an incoming call. I need to attach the audiovideoflow to the recorder, but I am not sure on how to do it. I will appreciate any help.
Apologies on the unformatted code, I am not sure how to format it properly, I tried.
Thanks.
Kris
Client B Code:
Accepts an incoming call
Records the media received in the incoming call. ***This is the part I have trouble
using System;
using System.Threading;
using Microsoft.Rtc.Collaboration;
using Microsoft.Rtc.Collaboration.AudioVideo;
using Microsoft.Rtc.Signaling;
using Microsoft.Rtc.Collaboration.Lync;
namespace Microsoft.Rtc.Collaboration.LyncUAS
{
public class LyncUAS
{
#region Locals
private LyncUASConfigurationHelper _helper;
private UserEndpoint _userEndpoint;
private AudioVideoCall _audioVideoCall;
private AudioVideoFlow _audioVideoFlow;
private Conversation _incomingConversation;
//Wait handles are only present to keep things synchronous and easy to read.
private AutoResetEvent _autoResetEvent = new AutoResetEvent(false);
private EventHandler<AudioVideoFlowConfigurationRequestedEventArgs> _audioVideoFlowConfigurationRequestedEventHandler;
private EventHandler<MediaFlowStateChangedEventArgs> _audioVideoFlowStateChangedEventHandler;
private AutoResetEvent _waitForAudioVideoCallEstablishCompleted = new AutoResetEvent(false);
private AutoResetEvent _waitForAudioVideoFlowStateChangedToActiveCompleted = new AutoResetEvent(false);
private AutoResetEvent _waitForPrepareSourceCompleted = new AutoResetEvent(false);
#endregion
#region Methods
/// <summary>
/// Instantiate and run the DeclineIncomingCall quickstart.
/// </summary>
/// <param name="args">unused</param>
public static void Main(string[] args)
{
LyncUAS lyncUAS = new LyncUAS();
lyncUAS.Run();
}
private void Run()
{
string filename = "received.wma";
_helper = new LyncUASConfigurationHelper();
// Create a user endpoint, using the network credential object
// defined above.
_userEndpoint = _helper.CreateEstablishedUserEndpoint("Lync UAS" /*endpointFriendlyName*/);
_userEndpoint.RegisterForIncomingCall<AudioVideoCall>(On_AudioVideoCall_Received);
Console.WriteLine("Waiting for incoming call...");
_autoResetEvent.WaitOne();
Console.WriteLine("came after call is connected");
//start recording for audio.
Recorder recorder = new Recorder();
recorder.StateChanged += new EventHandler<RecorderStateChangedEventArgs>(recorder_StateChanged);
recorder.VoiceActivityChanged += new EventHandler<VoiceActivityChangedEventArgs>(recorder_VoiceActivityChanged);
//**********This is the issue, currently _audioVideoFlow is null, it is not attached to the flow
//So this will fail, how to attach _audioVideoFlow to an incoming call ?? HELP !!!
// recorder.AttachFlow(_audioVideoFlow); ------------> HELP!
WmaFileSink sink = new WmaFileSink(filename);
recorder.SetSink(sink);
recorder.Start();
Console.WriteLine("Started Recording ...");
_autoResetEvent.WaitOne();
recorder.Stop();
Console.WriteLine("Stopped Recording ...");
recorder.DetachFlow();
Console.WriteLine("Exiting");
Thread.Sleep(2000);
}
private void audioVideoFlow_StateChanged(object sender, MediaFlowStateChangedEventArgs e)
{
Console.WriteLine("Flow state changed from " + e.PreviousState + " to " + e.State);
//When flow is active, media operations can begin
if (e.State == MediaFlowState.Active)
{
// Flow-related media operations normally begin here.
_waitForAudioVideoFlowStateChangedToActiveCompleted.Set();
}
// call sample event handler
if (_audioVideoFlowStateChangedEventHandler != null)
{
_audioVideoFlowStateChangedEventHandler(sender, e);
}
}
void recorder_VoiceActivityChanged(object sender, VoiceActivityChangedEventArgs e)
{
Console.WriteLine("Recorder detected " + (e.IsVoice ? "voice" : "silence") + " at " + e.TimeStamp);
}
void recorder_StateChanged(object sender, RecorderStateChangedEventArgs e)
{
Console.WriteLine("Recorder state changed from " + e.PreviousState + " to " + e.State);
}
void On_AudioVideoCall_Received(object sender, CallReceivedEventArgs<AudioVideoCall> e)
{
//Type checking was done by the platform; no risk of this being any
// type other than the type expected.
_audioVideoCall = e.Call;
// Call: StateChanged: Only hooked up for logging, to show the call
// state transitions.
_audioVideoCall.StateChanged += new
EventHandler<CallStateChangedEventArgs>(_audioVideoCall_StateChanged);
_incomingConversation = new Conversation(_userEndpoint);
Console.WriteLine("Call Received! From: " + e.RemoteParticipant.Uri + " Toast is: " +e.ToastMessage.Message);
_audioVideoCall.BeginAccept(
ar =>
{
try {
_audioVideoCall.EndAccept(ar);
Console.WriteLine("Call must be connected at this point. "+_audioVideoCall.State);
_autoResetEvent.Set();
} catch (RealTimeException ex) { Console.WriteLine(ex); }
}, null);
}
//Just to record the state transitions in the console.
void _audioVideoCall_StateChanged(object sender, CallStateChangedEventArgs e)
{
Console.WriteLine("Call has changed state. The previous call state was: " + e.PreviousState +
" and the current state is: " + e.State);
if (e.State == CallState.Terminated)
{
Console.WriteLine("Shutting down");
_autoResetEvent.Set();
_helper.ShutdownPlatform();
}
}
#endregion
}
}
I think I have figured out what's not quite right here.
Your Code
// Create a user endpoint, using the network credential object
// defined above.
_userEndpoint = _helper.CreateEstablishedUserEndpoint("Lync UAS" /*endpointFriendlyName*/);
_userEndpoint.RegisterForIncomingCall<AudioVideoCall>(On_AudioVideoCall_Received);
Console.WriteLine("Waiting for incoming call...");
_autoResetEvent.WaitOne();
Console.WriteLine("came after call is connected");
//start recording for audio.
Recorder recorder = new Recorder();
recorder.StateChanged += new EventHandler<RecorderStateChangedEventArgs>(recorder_StateChanged);
recorder.VoiceActivityChanged += new EventHandler<VoiceActivityChangedEventArgs>(recorder_VoiceActivityChanged);
//**********This is the issue, currently _audioVideoFlow is null, it is not attached to the flow //So this will fail, how to attach _audioVideoFlow to an incoming call ?? HELP !!!
// recorder.AttachFlow(_audioVideoFlow); ------------> HELP!
Looking good so far. I'm assuming you're establishing and such in your CreateEstablishedUserEndpoint method, but I'm not seeing where you're getting the value for _audioVideoFlow.
I'm guessing you might be doing it elsewhere, but on the off chance that's actually where you're running into problems, here's that bit:
Simplest pattern to get AVFlow
public static void RegisterForIncomingCall(LocalEndpoint localEndpoint)
{
localEndpoint.RegisterForIncomingCall
<AudioVideoCall>(IncomingCallDelegate);
}
private static void IncomingCallDelegate(object sender, CallReceivedEventArgs<AudioVideoCall> e)
{
e.Call.AudioVideoFlowConfigurationRequested += IncomingCallOnAudioVideoFlowConfigurationRequested;
}
private static void IncomingCallOnAudioVideoFlowConfigurationRequested(object sender, AudioVideoFlowConfigurationRequestedEventArgs e)
{
AudioVideoFlow audioVideoFlow = e.Flow; // <--- There's your flow, gentleman.
}
Now, instead of registering for your incoming call, just call RegisterForIncomingCall(_userEndpoint);.
Your AVFlow will be hanging off e.Flow above, you could then pass that into your recorder: recorder.AttachFlow(e.Flow) or simply assign the flow to a field in your class and autoResetEvent.WaitOne(); and set that up where you're setting that up now.
Obviously this is a pretty naive implementation. A lot can go wrong in those few lines of code (exception handling/static event handler memory leak comes immediately to mind); don't forget to wire up events related to status changes on the conversation/call and endpoints, as well as any of the recovery related items.

Find server details when connection lost with client

I have a code to access multiple wcf server from one client with multiple instances. if any connection lost between this, having faulted/closed event trigger function to hande this.
((ICommunicationObject)notificationProviderClient).Faulted += new EventHandler(myHost_Faulted);
((ICommunicationObject)notificationProviderClient).Closed += new EventHandler(myHost_Closed);
void myHost_Faulted(object sender, EventArgs e)
{
}
void myHost_Closed(object sender, EventArgs e)
{
}
The above function get called, if any connection get fault/closed.
In this scenarion how to find which wcf server connection lost with the clent? is there any possible to find this or we have to go for another method to handle this?
to find remote address of server during connection lost, use this on client side
this.notificationProviderClient.InnerDuplexChannel.Faulted += new EventHandler(myHost_Faulted);
void myHost_Faulted(object sender, EventArgs e) {
IContextChannel channel = sender as IContextChannel;
if (channel != null)
{
var remoteAddrs = a1.RemoteAddress;
}
}

DOTMsn is not firing the SingedIn event

I have just started building a app using “XihSolutions.DotMSN.dll” version: 2.0.0.40909,
My problem is that it is not firing the “Nameserver_SignedIn” event. Not sure if I am doing something wrong.
your help will be really helpful.
void Nameserver_SignedIn(object sender, EventArgs e)
{
throw new Exception("User Signed In");
}
private string message = string.Empty;
void NameserverProcessor_ConnectionEstablished(object sender, EventArgs e)
{
message = "Connected";
SetMessage();
}
void SetMessage()
{
if (tbMessage.InvokeRequired)
tbMessage. Invoke(new ThreadStart(SetMessage));
else
tbMessage.Text += Environment.NewLine+ message;
}
private void btnSingIn_Click(object sender, EventArgs e)
{
if (messenger.Connected)
{
// SetStatus("Disconnecting from server");
messenger.Disconnect();
}
// set the credentials, this is ofcourse something every DotMSN program will need to
// implement.
messenger.Credentials.Account = tbUserName.Text;
messenger.Credentials.Password = tbPwd.Text;
// inform the user what is happening and try to connecto to the messenger network.
//SetStatus("Connecting to server");
messenger.Connect();
}
You might use MSNPSharp instead - DotMSN is old and may not support the current MSN protocol. There link is here:
http://code.google.com/p/msnp-sharp/