I'm creating two queues in code if they don't already exist at Page_Load. The code runs fine for the first queue, but failed to set its Authenticate property on the second queue. I'm running Visual Studio as Administrator and can create those queues with the MSMQ UI. Both queues were created when I look in the UI, but the second one didn't have the property set.
if (MessageQueue.Exists(path1) == false)
{
var q = MessageQueue.Create(path1, true);
q.Authenticate = true;
}
if (MessageQueue.Exists(path2) == false)
{
var q = MessageQueue.Create(path2, true); // <-- didn't fail here
q.Authenticate = true; // <-- failed here
}
Error message:
The queue does not exist or you do not have sufficient permissions to perform the operation.
Related
I am trying to write some unit tests to verify all of my queue operations are working as expected, but I have run into the strangest situation:
I have the following code in my [TestInitialize] method:
var ns = NamespaceManager.CreateFromConnectionString(config.ServiceBusConnectionString);
var queueDescription = ns.GetQueue("happy-birthday");
Client = QueueClient.CreateFromConnectionString(config.QueueConnectionString, ReceiveMode.ReceiveAndDelete);
if (queueDescription.MessageCount > 0)
{
while (Client.Peek() != null)
{
var msg = Client.Receive();
msg.Complete();
}
}
My queue has a few Active Messages (confirmed with the queueDescription object) and the Azure portal confirms there should be two active messages that should be "completed" by the code above. However, Client.Receive() just stalls the code for a 30 second wait, then returns null.
I do not understand why the Client.Peek() returns the message, but when I called Client.Receive() i get a null returned.
I identified the problem was due to my assumption of what "Deferred" means.
I assumed deferred was the way I en-queued the same message back into the queue, when in fact deferred messages are set aside, and must be processed directly by retrieving the message by sequence number.
I was able to retrieve the message following these steps:
Peeked at the message
Confirmed State == Deferred
used the peek message to get the SequenceNumber, and retrieve it directly from the queue
mark the message as complete
this was the way I was able to get the message queue empty.
NameSpace = NamespaceManager.CreateFromConnectionString(ConnectionString);
var queueInfo = NameSpace.GetQueue("happy-birthday");
Client = QueueClient.CreateFromConnectionString(connectionString, "happy-birthday");
if (queueInfo.MessageCount > 0)
{
var message = Client.Peek();
while (message != null)
{
if (message.State == MessageState.Deferred)
{
message = Client.Receive(message.SequenceNumber);
}
else
{
message = Client.Receive();
}
message.Complete();
message = Client.Peek();
}
}
Scenario
Static Service Broker Queue and Service
Use these static queues for SQLDependency subscription
Rough outline of code
Using this blog post as a template the code roughly follows this pattern
SqlDependency.Start(this.dbConnectionString, this.notificationQueueName);
Configure Dependency targeting specific service (see code below)
private async void ConfigureDependencyUsingStoreProcedureAndSpecificQueue()
{
if (null != this.sampleSqlDependency)
{
this.sampleSqlDependency.OnChange -= null;
}
if (null != this.sampleSqlCommand)
{
this.sampleSqlCommand.Dispose();
}
if (null != this.sampleSqlConnection)
{
this.sampleSqlConnection.Dispose();
}
this.sampleSqlDependency = null;
this.sampleSqlCommand = null;
this.sampleSqlConnection = null;
//// Create connection.
this.sampleSqlConnection = new SqlConnection(this.dbConnectionString);
//// Create command.
this.sampleSqlCommand = new SqlCommand { Connection = this.sampleSqlConnection };
this.sampleSqlCommand.CommandType = CommandType.StoredProcedure;
this.sampleSqlCommand.CommandText = this.notificationStoredProcedure;
this.sampleSqlCommand.Notification = null;
//// Create Sql Dependency.
this.sampleSqlDependency = new SqlDependency(this.sampleSqlCommand, "service=" + this.notificationServiceName +"; Local database=" + this.databaseName, this.notificationTimeout);
this.sampleSqlDependency.OnChange += this.SqlDependencyOnChange;
await this.sampleSqlCommand.Connection.OpenAsync();
await this.sampleSqlCommand.ExecuteReaderAsync(CommandBehavior.CloseConnection);
if (null != this.sampleSqlCommand)
{
this.sampleSqlCommand.Dispose();
}
if (null != this.sampleSqlConnection)
{
this.sampleSqlConnection.Dispose();
}
Handle SqlDependencyOnChange event as below. Calling the ConfigureDependency code again
private void SqlDependencyOnChange(object sender, SqlNotificationEventArgs eventArgs)
{
if (eventArgs.Info == SqlNotificationInfo.Invalid)
{
Console.WriteLine("The above notification query is not valid.");
}
else
{
Console.WriteLine("\nNotification Time: {0}", DateTime.Now);
Console.WriteLine("\nNotification Info: " + eventArgs.Info);
Console.WriteLine("Notification source: " + eventArgs.Source);
Console.WriteLine("Notification type: " + eventArgs.Type + "\n");
}
switch (optionSelected)
{
case "1":
this.ConfigureDependencyUsingStoreProcedureAndDefaultQueue();
break;
case "2":
this.ConfigureDependencyUsingStoreProcedureAndSpecificQueue();
break;
case "3":
this.ConfigureDependencyUsingTextQueryAndDefaultQueue();
break;
case "4":
this.ConfigureDependencyUsingTextQueryAndSpecificQueue();
break;
}
}
Upon app shutdown call SqlDependency.Stop(this.dbConnectionString, this.notificationQueueName);. This returns true which according to the documentation means the listener was completely stopped.
Issue Faced
What I then see is that when the subscription reaches it's timeout period, it fires and drops a message onto the dependency queue waiting to be consumed.
If these messages stay in the queue, on next startup the app throws The given key was not present in the dictionary.
Also if I call SQLDependency.Stop() and leave the app running, it still consumes the QN fires for timeouts.
What step am I missing here as I am likely to face issues if messages are getting dropped on the static queue causing the The given key was not present in the dictionary exception.
Thanks
This returns true which according to the documentation means the listener was completely stopped.
This makes no promise with regard to the server state, nor the queue state. These will outlive your volatile application state, and at the next startup, you will find notifications from when your app was offline/shut down. You will have to code accordingly, with this expectation in place (eg. ignore keys that are not in the dictionary).
Note that even if SqlDependency.Stop() would attempt to stop the pending subscribed notifications, it is impossible to guarantee success as there could be notifications in transit (ie. pending delivery via Service Broker, notification may be in sys.transmission_queue). Waiting for all in transit notifications to drain delivery is also not feasible.
Additionally, your application would not handle backup-restore scenarios, as it is now. A restored backup may contain pending notification requests which will be invalidated upon restore and fire the notification message. When the application connects, it will find those unexpected notifications.
And ultimately, the application would not be able to handle its own disconnects/crashes. If you are relying on SqlDependency.Stop() to succeed before you can start successfully next time, you won't be able to start at all if you could not call SqlDependency.Stop() (=> any non-graceful stop).
For all these reasons, you must be able to handle keys not in the dictionary.
I have two self hosted services running on the same network. The first is sampling an excel sheet (or other sources, but for the moment this is the one I'm using to test) and sending updates to a subscribed client.
The second connects as a client to instances of the first client, optionally evaluates some formula on these inputs and the broadcasts the originals or the results as updates to a subscribed client in the same manner as the first. All of this is happening over a tcp binding.
My problem is occuring when the second service attempts to subscribe to two of the first service's feeds at once, as it would do if a new calculation is using two or more for the first time. I keep getting TimeoutExceptions which appear to be occuring when the second feed is subscribed to. I put a breakpoint in the called method on the first server and stepping through it, it is able to fully complete and return true back up the call stack, which indicates that the problem might be some annoying intricacy of WCF
The first service is running on port 8081 and this is the method that gets called:
public virtual bool Subscribe(int fid)
{
try
{
if (fid > -1 && _fieldNames.LeftContains(fid))
{
String sessionID = OperationContext.Current.SessionId;
Action<Object, IUpdate> toSub = MakeSend(OperationContext.Current.GetCallbackChannel<ISubClient>(), sessionID);//Make a callback to the client's callback method to send the updates
if (!_callbackList.ContainsKey(fid))
_callbackList.Add(fid, new Dictionary<String, Action<Object, IUpdate>>());
_callbackList[fid][sessionID] = toSub;//add the callback method to the list of callback methods to call when this feed is updated
String field = GetItem(fid);//get the current stored value of that field
CheckChanged(fid, field);//add or update field, usually returns a bool if the value has changed but also updates the last value reference, used here to ensure there is a value to send
FireOne(toSub, this, MakeUpdate(fid, field));//sends an update so the subscribing service will have a first value
return true;
}
return false;
}
catch (Exception e)
{
Log(e);//report any errors before returning a failure
return false;
}
}
The second service is running on port 8082 and is failing in this method:
public int AddCalculation(string name, string input)
{
try
{
Calculation calc;
try
{
calc = new Calculation(_fieldNames, input, name);//Perform slow creation before locking - better wasted one thread than several blocked ones
}
catch (FormatException e)
{
throw Fault.MakeCalculationFault(e.Message);
}
lock (_calculations)
{
int id = nextID();
foreach (int fid in calc.Dependencies)
{
if (!_calculations.ContainsKey(fid))
{
lock (_fieldTracker)
{
DataRow row = _fieldTracker.Rows.Find(fid);
int uses = (int)(row[Uses]) + 1;//update uses of that feed
try
{
if (uses == 1){//if this is the first use of this field
SubServiceClient service = _services[(int)row[ServiceID]];//get the stored connection (as client) to that service
service.Subscribe((int)row[ServiceField]);//Failing here, but only on second call and not if subscribed to each seperately
}
}
catch (TimeoutException e)
{
Log(e);
throw Fault.MakeOperationFault(FaultType.NoItemFound, "Service could not be found");//can't be caught, if this timed out then outer connection timed out
}
_fieldTracker.Rows.Find(fid)[Uses] = uses;
}
}
}
return id;
}
}
catch (FormatException f)
{
Log(f.Message);
throw Fault.MakeOperationFault(FaultType.InvalidInput, f.Message);
}
}
The ports these are on could change but are never shared. The tcp binding used is set up in code with these settings:
_tcpbinding = new NetTcpBinding();
_tcpbinding.PortSharingEnabled = false;
_tcpbinding.Security.Mode = SecurityMode.None;
This is in a common library to ensure they both have the same set up, which is also a reason why it is declared in code.
I have already tried altering the Service Throttling Behavior for more concurrent calls but that didn't work. It's commented out for now since it didn't work but for reference here's what I tried:
ServiceThrottlingBehavior stb = new ServiceThrottlingBehavior
{
MaxConcurrentCalls = 400,
MaxConcurrentSessions = 400,
MaxConcurrentInstances = 400
};
host.Description.Behaviors.RemoveAll<ServiceThrottlingBehavior>();
host.Description.Behaviors.Add(stb);
Has anyone had similar issues of methods working correctly but still timing out when sending back to the caller?
This was a difficult problem and from everything I could tell, it is an intricacy of WCF. It cannot handle one connection being reused very quickly in a loop.
It seems to lock up the socket connection, though trying to add GC.Collect() didn't free up whatever resources it was contesting.
In the end the only way I found to work was to create another connection to the same endpoint for each concurrent request and perform them on separate threads. Might not be the cleanest way but it was all that worked.
Something that might come in handy is that I used the svc trace viewer to monitor the WCF calls to try and track the problem, I found out how to use it from this article: http://www.codeproject.com/Articles/17258/Debugging-WCF-Apps
I was developing application with Geofencing, when stuck at issue:
ArgumentException (Value does not fall within the expected range)
when I am trying to register background task for geofencing.
Sample from MSDN has the same problem. I will show code from sample for clarity (link to sample: http://code.msdn.microsoft.com/windowsapps/Geolocation-2483de66#content
use scenario 5,
http://msdn.microsoft.com/en-us/library/windows/apps/dn440583.aspx - instruction how to test).
All what I have done:
Build my app in Visual Studio.
Deploy the app locally first and add the app to the lock screen in Settings.
Close your app that is running locally.
Launch your app in the Visual Studio simulator.
Call RegisterBackgroundTask(..) (simply pressed button register in scenario 5)
There is code from MSDN sample that I have commented for successful app deploying in Simulator - tagged with ////// [my changes] ////////
async private void RegisterBackgroundTask(object sender, RoutedEventArgs e)
{
try
{
// Get permission for a background task from the user. If the user has already answered once,
// this does nothing and the user must manually update their preference via PC Settings.
//BackgroundAccessStatus backgroundAccessStatus = await BackgroundExecutionManager.RequestAccessAsync(); ////// [my changes] ////////
// Regardless of the answer, register the background task. If the user later adds this application
// to the lock screen, the background task will be ready to run.
// Create a new background task builder
BackgroundTaskBuilder geofenceTaskBuilder = new BackgroundTaskBuilder();
geofenceTaskBuilder.Name = SampleBackgroundTaskName;
geofenceTaskBuilder.TaskEntryPoint = SampleBackgroundTaskEntryPoint;
// Create a new location trigger
var trigger = new LocationTrigger(LocationTriggerType.Geofence);
// Associate the locationi trigger with the background task builder
geofenceTaskBuilder.SetTrigger(trigger);
// If it is important that there is user presence and/or
// internet connection when OnCompleted is called
// the following could be called before calling Register()
// SystemCondition condition = new SystemCondition(SystemConditionType.UserPresent | SystemConditionType.InternetAvailable);
// geofenceTaskBuilder.AddCondition(condition);
// Register the background task
geofenceTask = geofenceTaskBuilder.Register();
// Associate an event handler with the new background task
geofenceTask.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);
UpdateButtonStates(/*registered:*/ true);
////// [my changes] ////////
//switch (backgroundAccessStatus)
//{
// case BackgroundAccessStatus.Unspecified:
// case BackgroundAccessStatus.Denied:
// rootPage.NotifyUser("This application must be added to the lock screen before the background task will run.", NotifyType.ErrorMessage);
// break;
// default:
// // Ensure we have presented the location consent prompt (by asynchronously getting the current
// // position). This must be done here because the background task cannot display UI.
// GetGeopositionAsync();
// break;
//}
////// [my changes] ////////
}
catch (Exception ex)
{
// HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED) == 0x80070032
const int RequestNotSupportedHResult = unchecked((int)0x80070032);
if (ex.HResult == RequestNotSupportedHResult)
{
rootPage.NotifyUser("Location Simulator not supported. Could not get permission to add application to the lock screen, this application must be added to the lock screen before the background task will run.", NotifyType.StatusMessage);
}
else
{
rootPage.NotifyUser(ex.ToString(), NotifyType.ErrorMessage);
}
UpdateButtonStates(/*registered:*/ false);
}
}
Exception falls on string:
geofenceTask = geofenceTaskBuilder.Register();
Can anybody help me?
P.S. Same question thread on msdn - http://social.msdn.microsoft.com/Forums/en-US/3d69f2f9-93e0-401b-8a13-598dc671fa4f/backgroundtask-register?forum=winappswithcsharp
This is a known "bug" see Windows Store 8.1 Location background tasks do not work in simulator. I have yet to get an answer other than
Your issue has been routed to the appropriate VS development team for investigation
Please upvote it!
I am trying to programmatically get my site status from IIS to see if it's stopped, but I kept getting the following error,
The object identifier does not represent a valid object. (Exception from HRESULT: 0x800710D8)
The application is using ServerManager Site class to access the site status. Here is the code,
//This is fine, gets back the site
var serverManager = new Microsoft.Web.Administration.ServerManager(ConfigPath);
var site = serverManager.Sites.FirstOrDefault(x => x.Id == 5);
if (site == null) return;
var appPoolName = site.Applications["/"].ApplicationPoolName;
//error!
var state = site.State;
I've test with static site to isolate the issue, making sure that the site is up and running, all configuration are valid, point to the valid application pool...etc.
Let me know if you need more details. Is it the COM thing?
I figured out where the problem is. Basically, there are two parts to the Server manager, the first part of the server manager allows you to read site details from configuration file, which is what I've been doing above. The problem with that is you will only able get the information that's in file and site state is not part of it.
The second part of the Server Manager allows you to connect to the IIS directly and it does this by interacting with the COM element. So what I should be doing is this:
ServerManager manager= ServerManager.OpenRemote("testserver");
var site = manager.Sites.First();
var status = site.State.ToString() ;
I had a similar problem but mine was caused by the delay needed to activate the changes from the call to CommitChanges on the ServerManager object. I found the answer I needed here:
ServerManager CommitChanges makes changes with a slight delay
It seems like polling is required to get consistent results. Something similar to this solved my problem (I got the exception when accessing a newly added application pool):
...
create new application pool
...
sman.CommitChanges();
int i = 0;
const int max = 10;
do
{
i++;
try
{
if (ObjectState.Stopped == pool.State)
{
write_log("Pool was stopped, starting: " + pool.Name);
pool.Start();
}
sman.CommitChanges();
break;
}
catch (System.Runtime.InteropServices.COMException e)
{
if (i < max)
{
write_log("Waiting for IIS to activate new config...");
Thread.Sleep(1000);
}
else
{
throw new Exception(
"CommitChanges timed out efter " + max + " attempts.",
e);
}
}
} while (true);
...