Is this business logic in my view model, and is it allowed? - c#

I have a WCF service that must be always up, and is therefore hosted by a Windows Service. My Windows Service model has simple startup code:
HostService:
public void StartService()
{
if (_hostController.Status != ServiceControllerStatus.Stopped && _hostController.Status != ServiceControllerStatus.StopPending)
{
var msg = string.Format("Service '{0}' must be in status '{1}' or '{2}' to accept a 'Start' command.",
HostResources.ServiceName, ServiceControllerStatus.Stopped, ServiceControllerStatus.StopPending);
throw new HostServiceException(msg, HostServiceException.HostServiceExceptionCategory.ServiceStatusControl);
}
try
{
_hostController.Start();
}
catch (Exception ex)
{
if (ex is Win32Exception || ex is InvalidOperationException)
{
throw new HostServiceException(string.Format("'{0}' failed to respond properly to a 'StartService` command: '{1}'", _hostController.ServiceName, ex.Message), ex);
}
throw;
}
try
{
_hostController.WaitForStatus(ServiceControllerStatus.Running, _waitForStatusTimeout);
}
catch (TimeoutException tx)
{
throw new HostServiceException(string.Format("{0} did not start respond after {1} seconds and the 'Start' command timed out.", _hostController.ServiceName, _waitForStatusTimeout.TotalSeconds), tx);
}
if (ServiceControllerStatus.Running != _hostController.Status)
{
throw new HostServiceException(string.Format("The 'StartService' command for '{0}' failed. The Service has a status of '{1}'.", _hostController.ServiceName, _hostController.Status));
}
}
My WCF service has even simpler startup code:
SchedulerService:
public void Start()
{
_isBusy = false;
var interval = _config.Settings.ServicePollingInterval * 1000;
_pollTimer = new Timer(interval);
_pollTimer.Enabled = true;
_pollTimer.Elapsed += PollTimerElapsed;
_pollTimer.Start();
Status = SchedulerServiceStatus.Running;
var msg = string.Format("'{0}' started with the timer set for {1} second{2} intervals.", SchedulerResources.ServiceName, _pollTimer.Interval / 1000, _pollTimer.Interval / 1000 > 1 ? "s" : "");
_logger.Info(msg);
StatusChanged(this, new SchedulerStatusChangeEventArgs(Status, msg));
}
It is the code in my view model in question here, because only if it can start the Windows Service, will it start the WCF service:
SchedulerViewModel:
private void ExecuteStart()
{
if (_hostModel.ServiceStatus != ServiceControllerStatus.Running)
{
_logger.Warn("The '" + _hostModel.ServiceName + "' host service is not running. The '" + GetType().Name + "' will attempt to start it.");
try
{
_hostModel.StartService();
}
catch (Exception ex)
{
var msg = string.Format("The '{0}' could not start the '{1}' host service: {2}", GetType().Name, _hostModel.ServiceName, ex.Message);
_logger.Error(msg, ex);
throw new HostServiceException(msg, HostServiceException.HostServiceExceptionCategory.ServiceController, ex);
}
}
try
{
_scheduler.Start();
}
catch (Exception ex)
{
throw new SchedulerServiceException(ex.Message, SchedulerServiceException.SchedulerServiceExceptionCategory.SchedulerControl, ex);
}
SchedulerStatus = _scheduler.Status;
CommandsCanExecuteChanged();
}
Now this is indeed not view logic, but it is hardly business logic either; more like housekeeping: I can only use the washing machine if the water supply is switched on. Now I don't really see the need for a whole new model with just an instance of HostModel and SchedulerService, just for this decision. What say the jury on my current setup?

I would push all the code behind another service and inject this via an interface into the VM, I'd do this becuase I presume the WCF expose state via events and you want to display this in the UI. If you push this behind another service allows to 'shape' the exposed state into a more UI centric model suited for use in the VM.
If you did this, from the view point of the VM all it would then know about is 'start\stop' methods and an event handler - the implementation is then abstracted away and makes testing the VM very easy via mocking.
To take this further I would consider using Reactive extensions instead of CLR events for communicating state changes in the service.

Related

Azure Service Bus 3.2.2 BeginReceive()

I need to upgrade our service bus nuget package to 3.2.2 (think the evenprocessor host requires it) but I have always kept our service bus project lib at 2.8.2. This is mainly due to the fact that BeginReceive() and EndReceive() looks to have been removed. Is there any reason or anyway I can easily convert this
public void StartReceiving(RecieverCallback callback, TimeSpan waittime, object state = null)
{
this._recieverCallback = callback;
_queueClient = this.MessagingFactory.CreateQueueClient(QueueName, ReceiveMode);
// make initial async call
_asyncresult = _queueClient.BeginReceive(waittime, ReceiveDone, _queueClient);
}
public void ReceiveDone(IAsyncResult result)
{
if (result != null)
{
try
{
var tmpClient = result.AsyncState as QueueClient;
var brokeredMessage = tmpClient.EndReceive(result);
if (brokeredMessage != null)
{
if (ReceiveMode == ReceiveMode.PeekLock)
{
brokeredMessage.Complete();
}
var tmpMessage = brokeredMessage.GetBody<T>();
ProcessMessageProperties(tmpMessage, brokeredMessage);
_recieverCallback(tmpMessage);
}
}
catch (Exception ex)
{
_logger.Fatal("ReceiveDone: {0}", ex.Message);
Console.WriteLine(ex.Message);
}
}
// do recieve for next message
_asyncresult = _queueClient.BeginReceive(ReceiveDone, _queueClient);
}
Image showing the error
Following image shows what happens if I upgrade servicebus to 3.2.2 which I believe will solve the original error (program running 3.2.2, lib project running 2.8.x)
I figured it out see link
https://gist.github.com/sitereactor/8953583
If anyone has a similar issue, let me know and will post my code but its 95% the same as per the link.

UI of Process is not visible after Process.Start()

I have made a WCF Service and it contains a method string SaveVideoInformation()
The purpose of this method is to run a process if it is not running.
Following is the code of that method.
public string SaveVideoInformation(string ID, string videoName)
{
string Result = null;
try
{
Result = Insert(ID, videoName);
Process[] pname = Process.GetProcessesByName("AutoRunVideoWaterMarkingTook");
if (pname.Length == 0)
{
Result += " | Trying to run Process";
try
{
Process process = Process.Start(#"~\Debug\AutoRunVideoWaterMarkingTook.exe");
Result += " | Process Ran Successfully";
}
catch (Exception ex)
{
Result += " | Exception While Running the process";
throw new Exception("Unable to start Process);
}
}
else
{
Result += "|Process Already Running";
}
}
catch (Exception ex)
{
Result = "Not Done," + ex.Message;
}
return Result;
}
The problem I am facing is when i call this method from Windows Form Tool Application, it run successfully and i can see the UI.
but when i call this method from Windows Service, Process Starts but its UI is not visible.
That is most likely because your Windows Service is not in user interactive mode.
You have to enable this from the Services panel, as described in this blog: Check the Allow service to interact with desktop in the service properties Log On page.
Also read Microsofts recommendations on user interactive services.

Pusher for Windows Phone failing to disconnect

I have encountered a problem with pusherClient.wp8 package I installed from Nuget. Every time the app is sent to the background, I disconnect from pusher and unsubscribe from the channel. when I resume the app, the code hang when connection is re-established with pusher.
I have tried to reset the pusher object, reset the channel, create a new instance of pusher, and still nothing works, it seems there is a problem with the package, or rather the websocket disconnect method is failing to disconnect from pusher, however, when I close the app, everything get reseted. but this does not help me in instances when a user open a photopicker from my app.
Does anyone has a suggestion or know of another pusherclient I can use for windows phone 8. I have been struggling with this problem for weeks now.
Here is the github link of the package I used: https://github.com/bszypelow/PusherClient.WP8/blob/master/PusherClient.WP8
Thank you
public ConnectionState Connect()
{
var task = Task.Run(async () => await pusher.ConnectAsync()); ;
try
{
task.Wait();
}
catch (Exception ex)
{
Debug.WriteLine("Exception " + ex.Message + " at " + ex.Source + "Inner exception " + ex.InnerException + " additional data " + ex.Data);
}
return task.Result;
}
From looking at the source code I have a guess:
All the async methods never use .ConfigureAwait(false) which could be a reason for the dead lock.
Especially if you call it from the UI thread using the .Wait() or .Result. From event for example.
I suggest you to update the code (it's MIT license, you can do that):
public Task<Channel> Subscribe(string channelName)
{
if (_connection.State != ConnectionState.Connected)
throw new PusherException("You must wait for Pusher to connect before you can subscribe to a channel", ErrorCodes.NotConnected);
if (Channels.ContainsKey(channelName))
{
return Task.FromResult(Channels[channelName]);
}
// If private or presence channel, check that auth endpoint has been set
var chanType = ChannelTypes.Public;
if (channelName.ToLower().StartsWith("private-"))
chanType = ChannelTypes.Private;
else if (channelName.ToLower().StartsWith("presence-"))
chanType = ChannelTypes.Presence;
return SubscribeToChannel(chanType, channelName); //await is not needed here
}
private async Task<Channel> SubscribeToChannel(ChannelTypes type, string channelName)
{
switch (type)
{
case ChannelTypes.Public:
Channels.Add(channelName, new Channel(channelName, this));
break;
case ChannelTypes.Private:
AuthEndpointCheck();
Channels.Add(channelName, new PrivateChannel(channelName, this));
break;
case ChannelTypes.Presence:
AuthEndpointCheck();
Channels.Add(channelName, new PresenceChannel(channelName, this));
break;
}
if (type == ChannelTypes.Presence || type == ChannelTypes.Private)
{
string jsonAuth = await _options.Authorizer.Authorize(channelName, _connection.SocketID)
.ConfigureAwait(false); //do not capture the context!!
var template = new { auth = String.Empty, channel_data = String.Empty };
var message = JsonConvert.DeserializeAnonymousType(jsonAuth, template);
_connection.Send(JsonConvert.SerializeObject(new { #event = Constants.CHANNEL_SUBSCRIBE, data = new { channel = channelName, auth = message.auth, channel_data = message.channel_data } }));
}
else
{
// No need for auth details. Just send subscribe event
_connection.Send(JsonConvert.SerializeObject(new { #event = Constants.CHANNEL_SUBSCRIBE, data = new { channel = channelName } }));
}
return Channels[channelName];
}
You can checkout the source code, than if you don't use it now you can install trial version of ReSharper and this plug-in. They will help you to find all the lines where .ConfigureAwait is missing.

WCF Data Service BeginSaveChanges runs only once

I have the following WCF Data Service code in a Xamarin Forms application.
It updates a simple row in a table.
Static.Dialogs.Alert("Starting");
DataServiceQuery<SRef.SimpleObject> query = (DataServiceQuery<SRef.SimpleObject>)Entities.SimpleObject.Where(x => x.ID == Guid.Parse("DEF47A0F-AF1E-4043-B8C8-56084841E80B"));
query.BeginExecute((result) =>
{
try
{
Static.Dialogs.Alert("Getting the object");
var actData = query.EndExecute(result).FirstOrDefault();
if (actData != null)
{
actData.Info = "Info"+randomNumber;
Entities.UpdateObject(actData);
Entities.ChangeState(actData, EntityStates.Modified);
Static.Dialogs.Alert("Before the update");
Entities.BeginSaveChanges(SaveChangesOptions.BatchWithIndependentOperations, (result2) =>
{
try
{
Static.Dialogs.Alert("BeginSaveChanges starts");
var r = Entities.EndSaveChanges(result2);
Static.Dialogs.Alert("Update done ");
}
catch (Exception ex2)
{
Static.Dialogs.Alert("Error:" + ex2.Message);
}
}, null);
}
else
Static.Dialogs.Alert("No object");
}
catch (Exception ex1)
{
Static.Dialogs.Alert("Error:" + ex1.Message);
}
}, null);
}
catch (Exception ex)
{
Static.Dialogs.Alert("Error:" + ex.Message);
}
});
I have tested it on an emulator and a physical device.
Sometimes it works perfectly.
Sometimes I get only these messages:
Starting
Getting the object
Before the update
Sometimes only these:
Starting
It mostly gets wrong when I get a perfect update and I try again. Like it has 'used up' the only connection and after that it doesn't work.
On the server side I log every error and nothing is catched there. Also, no exception on the client side.
The DataServiceContext MergeOption is set to PreserveChanges.
What could affect it? When I send out a request, I have to wait some time? Should I close the connection somehow?
I reckon it is some kind of cache problem.
UPDATE:
I tried again, with a simpler approach (I only save a new item now):
private DataServiceReference.DataEntities entities;
public DataServiceReference.DataEntities Entities
{
get
{
if (entities == null)
{
entities = new DataServiceReference.DataEntities(Static.BaseURI);
entities.MergeOption = MergeOption.OverwriteChanges;
entities.SaveChangesDefaultOptions = SaveChangesOptions.ReplaceOnUpdate;
}
return entities;
}
}
var newItem = new DataServiceReference.Info()
{
Name = "Name " + DateTime.Now.Second,
ID = Guid.NewGuid(),
Role = "1"
};
Entities.AddToInfo(newItem);
try
{
foreach (var item in Entities.Entities)
{
System.Diagnostics.Debug.WriteLine(item.Identity + " " + item.State);
}
var res = Entities.BeginSaveChanges(SaveChangesOptions.Batch,
(result) =>
{
//var s = 3; //debug point - only hit once
try
{
//back to the UI thread
Xamarin.Forms.Device.BeginInvokeOnMainThread(() =>
//(result.AsyncState as DataServiceReference.DataEntities).EndSaveChanges(result));
Entities.EndSaveChanges(result));
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
throw;
}
}, Entities);
//res.AsyncWaitHandle.WaitOne(1000); //it only blocks the main thread, no use
resultList.Add(newItem.Name);
}
catch (Exception ex2)
{
System.Diagnostics.Debug.WriteLine(ex2.Message);
throw;
}
I also read (and it was pointed out in the first answer) that the result is provided on a different thread, so I added a dispatcher call to get the results (note the UI thread call: Xamarin.Forms.Device.BeginInvokeOnMainThread).
In an application where the callback must be invoked on a specific
thread, you must explicitly marshal the execution of the End method,
which handles the response, to the desired thread. For example, in
Windows Presentation Foundation (WPF)-based applications and
Silverlight-based applications, the response must be marshaled back to
the UI thread by using the BeginInvoke method on the Dispatcher
object.
Note the mentioning of the End method!
I added the following debug message:
foreach (var item in Entities.Entities)
{
System.Diagnostics.Debug.WriteLine(item.Identity + " " + item.State);
}
The result:
[0:]http://192.168.1.100/InfoDataService/InfoDataService.svc/Info(guid'f1057131-90ee-11d7-9812-0040f6cc1384') Unchanged
[0:]http://192.168.1.100/InfoDataService/InfoDataService.svc/Info(guid'f1057133-90ee-11d7-9812-0040f6cc1384') Unchanged
[0:]http://192.168.1.100/InfoDataService/InfoDataService.svc/Info(guid'f6cfce91-90ef-11d7-9812-0040f6cc1384') Unchanged
[0:]http://192.168.1.100/InfoDataService/InfoDataService.svc/Info(guid'a6c2d822-91a7-11d7-9813-0040f6cc1384') Unchanged
[0:]http://192.168.1.100/InfoDataService/InfoDataService.svc/Info(guid'a6c2d823-91a7-11d7-9813-0040f6cc1384') Unchanged
[0:]http://192.168.1.100/InfoDataService/InfoDataService.svc/Info(guid'a6c2d824-91a7-11d7-9813-0040f6cc1384') Unchanged
[0:]http://192.168.1.100/InfoDataService/InfoDataService.svc/Info(guid'b750e561-91b8-11d7-9813-0040f6cc1384') Unchanged
[0:]http://192.168.1.100/InfoDataService/InfoDataService.svc/Info(guid'b750e562-91b8-11d7-9813-0040f6cc1384') Unchanged
[0:]http://192.168.1.100/InfoDataService/InfoDataService.svc/Info(guid'b750e563-91b8-11d7-9813-0040f6cc1384') Unchanged
[0:]http://192.168.1.100/InfoDataService/InfoDataService.svc/Info(guid'eee2d1f7-17cb-4283-a053-01f6cf7bb2fd') Unchanged
[0:] Added
[0:] Added
[0:] Added
It seems, that the context keeps gathering the objects but it sends only the first new object to the service and the other objects keep piling up.
The article emphasizes the thread issues of the End method, but the callback is the real issue here (it is not fired), so we never get to the End call and the UI thread.
This seems like a serious bug and I can't tell what to do...
The reason is that BeginExecute will start another thread, and your main thread returned even when the sub-thread doesn't finished. Then this code may even not execute the BeginSaveChanges.
So to make sure all the sub threads finished. The main thread need to wait for the sub threads.
The simplest way is to System.Threading.Thread.Sleep(5000); Or you can use IAsyncResult.AsyncWaitHandle.WaitOne()

Installing windows service Using C# gives error

Im working in windows service syncmysqldb.exe i need the service to run a process ie syncing of two mysql databases in n intervals of time given in setting.xml file
When i install this service service manager i see the service not in started state and when i try to run in manually by right clicking it gives following error
When i install service it gives following error
The description for Event ID ( 11001 ) in Source ( MsiInstaller ) cannot be found. The local computer may not have the necessary registry information or message DLL files to display messages from a remote computer. You may be able to use the /AUXSOURCE= flag to retrieve this description; see Help and Support for details. The following information is part of the event: Product: SetupSynMysqldb -- Error 1001. Error 1001. An exception occurred during the Commit phase of the installation. This exception will be ignored and installation will continue. However, the application might not function correctly after installation is complete. --> The savedState dictionary contains inconsistent data and might have been corrupted., (NULL), (NULL), (NULL), (NULL), , .
When i run service in service manager it gives following error
The SyncMysqlDb service failed to start due to the following error:
The system cannot find the file specified.
C# code
protected override void OnStart(string[] args)
{
try
{
//add this line to text file during start of service
EventLog.WriteEntry("SyncMysqlDb in OnStart. at " + DateTime.Now);
//handle Elapsed event
tmrSync.Elapsed += new ElapsedEventHandler(OnElapsedTime);
tmrSync.Interval = GetIntervals();
//enabling the timer
tmrSync.Enabled = true;
//TraceService(" tmrSync.Interval =" + tmrSync.Interval + " at " + DateTime.Now);
ThreadPool.QueueUserWorkItem(new WaitCallback(ServiceWorkerThread));
}
catch (Exception ex)
{
EventLog.WriteEntry("Service failed to start.", EventLogEntryType.Error, (int)Service1EventIds.Start_InitializationFailure, ex);
}
}
private void ServiceWorkerThread(object state)
{
// Periodically check if the service is stopping.
while (!this.stopping)
{
// Perform main service function here...
Thread.Sleep(2000); // Simulate some lengthy operations.
}
// Signal the stopped event.
this.stoppedEvent.Set();
}
protected override void OnStop()
{
tmrSync.Enabled = false;
//TraceService("stopping service" + DateTime.Now);
EventLog.WriteEntry("SyncMysqlDb in OnStop. at " + DateTime.Now);
this.stopping = true;
this.stoppedEvent.WaitOne();
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
try
{
EventLog.WriteEntry(#"Executing C:\SyncMysqlDbRepository\task.bat at " + DateTime.Now);
Process.Start(#"C:\SyncMysqlDbRepository\task.bat");
}
catch (Exception ex)
{
EventLog.WriteEntry("Service failed to start.at " + DateTime.Now, EventLogEntryType.Error, (int)Service1EventIds.Start_InitializationFailure, ex);
}
// TraceService("syncing db at " + DateTime.Now);
}
protected int GetIntervals()
{
var dt = new DataTable();
try
{
dt.ReadXmlSchema(#"C:\SyncMysqlDbRepository\SettingsDs.xml");
dt.ReadXml(#"C:\SyncMysqlDbRepository\Settings.xml");
}
catch (Exception ex)
{
EventLog.WriteEntry("GetIntervals failed at " + DateTime.Now, EventLogEntryType.Error, (int)Service1EventIds.Start_InitializationFailure, ex);
return 0;
}
return Convert.ToInt16(dt.Rows[0].ItemArray[2]); //Intervals from settings.xml
}

Categories

Resources