I have a desktop application and below is the flow that is to be followed.
During app initialization, an API should be hit and an excel should downloaded to a shared location. After download is complete the app should read the excel file. This won't be a problem with a single instance of app running. But since this is a desktop app, multiple instances (on different computers) are run, app every time during initialization, downloads the file. I'm using OLE Db engine to read the file and the file is being locked and there 's error "The ole db engine cannot read the file because it is opened by another user " while another instance of the app is opened. How to prevent this?
if (response.Result.IsSuccessStatusCode)
{
using (Stream streamToWriteTo = new FileStream(pathToDownloadReport, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
response.Result.Content.CopyToAsync(streamToWriteTo).Wait();
}
}
If you want to have concurrent access to a file you need to make sure every client only takes a read-lock on the file. With OleDb you can open a connection to the file with ReadOnly access with a connection.
"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=\\path\to\your\exelfile.xlsx;Extended Properties=\"Excel 12.0;IMEX=1;ReadOnly=true;\""
You still need to make sure no one opens the file in Excel.
Since you only can have read-only access to your file, you might as well make a local copy of the file and open that instead. That way locking won't be a problem.
Is this advisable to use Mutex object to synchronize request/response xmls writing for WCF service? Is there any better approach for it?
Background
We have one very old WCF service which uses by some other Java service and thousands of users use that.
To troubleshoot some prod issues I am implementing logging to capture all the request and response xmls so It will have huge logging.
Since multiple process are trying to write on same xml file i am getting IO exception and to resolve that I thought to use Mutex based on below link however my queries are
Is this advisable to use it for my service? thousands of requests would hit service in a day so my service would become slower due to mutex ?
what is the best solution for this type of situation. I am sure this is very common scenario where it is required to log lot to troubleshoot issues in WCF.
OR
LOCK OR Monitor Object should be ok in my case while wrinting to log file? my service is with ConcurrencyMode Multiple OR Mutix is required ?
System.ServiceModel.FaultException - The process cannot access the file 'xxx' because it is being used by another process
Note: Since this is very old service, i don't have an option to use Log4Net library here.
Thanks for your help.
Like below method I have around 30 methods which log request and response xml and for that I am getting IO error - file is in use.
Code
WebMethod1(object Request)
{
string requestId = Guid.newguid().tostring()
LogRequestResponse(Request)
response = CallOtherService();
LogRequestResponse(response);
}
LogRequestResponse(object xmlReqRes)
{
try
{
using(StreamWriter myWriter = new StreamWriter(filePath, true, Encoding.UTF8))
{
xmlSerializer mySerializer = new xmlSerializer(xmlReqRes.GetType())
mySerializer.Serialize(myWriter, xmlReqres);
}
}
catch {}
}
I've written a C# windows service which can write messages to a custom EventLog or to any number of files. These messages are all marked with some priority (so, for example, only ERRORs and WARNINGs get stored in the EventLog, but if desired a lot more can be stored to a file).
What I'd like to do now is create a GUI that can listen for these messages and display them in real-time. Allowing a user to watch the current messages (at whatever their desired priority level), without the need to store everything to a file. I assume this is a separate program with some form of hook into the service, but I'm unsure of where to start.
This is my first real windows service, so I seem to be missing some keywords for finding out how to do this... Are there any code samples, tutorials, references, etc. for how to do something like this?
UPDATE
A lot of helpful answers, I love it when there's many ways to solve a problem! I think I'm going to implement a self-hosting WCF based solution. I'm still very light on the details as I'm trying to learn about WCF (I believe it will prove quite useful for me in other projects)... but thus far, I've found the videos here to be the most helpful as an intro how-to.
What you can do is have the windows service have way of registering for an event (you can do this through using Windows Communication Foundation). When your error comes up, it fires that event, and your winforms app will be notified. It's called a duplex contract:
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/0eb69998-0388-4731-913e-fb205528d374/
http://msdn.microsoft.com/en-us/library/ms731184.aspx
Actually the really cool thing is that you can have multiple applications listening this way too. So you can display it on screen, and have another application log it etc. without the two external apps knowing anything about each other.
I know this has already been mentioned, but use Windows Communication Foundation (WCF). Specifically, use the Publish-Subscribe Framework developed by Juval Lowy, author of Programming WCF Services. The details are described in this excellent MSDN article, and the source code is available for free at Lowy's website.
The neat thing about this framework is that it decouples the publisher, e.g., your Windows service, from any subscribers, e.g., your GUI. The publisher "publishes" events that are of interest to the Pub/Sub Service, which is always available. From the publisher's point of view, it doesn't matter if there are any subscribers or not. The Pub/Sub Service takes care of routing events to any and all registered subscribers. In this way, your Windows service publishes events as they occur, your GUI will subscribe/unsubscribe to the Pub/Sub Service when it loads/exits, and the Pub/Sub Service will notify your GUI as events occur.
I have used this setup in my project, and it works extremely well.
I've actually used the BitFactory Logger that has a socket logger that you can use for this purpose.
What you're describing is inter-process communication, which can get messy.
The easiest and most elegant, but probably least reactive, is to have the service write entries as small text files (or append to a log), and have your GUI use a FileSystemWatcher to detect new files or updates to the log file, and read the file. You have to ensure that the service opens the file for appending in a "shared" manner, allowing read-only access while it's writing. Otherwise, you'll block one process or the other, probably causing lost messages.
Processes can communicate through some built-in pipelines. if your service writes messages to its StandardOutput pipe, the GUI can remotely attach a listener and receive events when messages are written. This is probably the most elegant non-file way to do what you want. Research the Process class, especially the OutputDataReceived event. You'll have to go look for the process from your GUI by some uniquely identifying information, using GetProcess().
You need to look for "synchronization" and "inter-process communication". In your case the service would use the global event or semaphore to signal presence of data, and GUI process would check event/semaphore state and read the updates from event log or from file.
There exist more complicated scenarios, but the above is a good starting point.
Observer pattern!
Perhaps a delegate for all observable models that you can hook into with your service?
.NET remoting over IPC channel.
I've found that a Named Pipe communication with a System Tray application was the simplest way to display notifications from a Windows Service. This is because in Windows 10 services run with different permissions than the logged in user, so the notification app needs to perform IPC with the service.
Here you could put this into the server:
using System;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleServerApp
{
class Program
{
static void Main(string[] args)
{
StartServer();
Task.Delay(1000).Wait();
}
static void StartServer()
{
Task.Factory.StartNew(() =>
{
var server = new NamedPipeServerStream("PipesOfPiece");
server.WaitForConnection();
StreamReader reader = new StreamReader(server);
StreamWriter writer = new StreamWriter(server);
while (true)
{
var line = reader.ReadLine();
writer.WriteLine(String.Join("", line.Reverse()));
writer.Flush();
}
});
}
}
}
Then put this into your client:
using System;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleClientApp
{
class Program
{
static void Main(string[] args)
{
//Client
var client = new NamedPipeClientStream("PipesOfPiece");
client.Connect();
StreamReader reader = new StreamReader(client);
StreamWriter writer = new StreamWriter(client);
while (true)
{
string input = Console.ReadLine();
if (String.IsNullOrEmpty(input)) break;
writer.WriteLine(input);
writer.Flush();
Console.WriteLine(reader.ReadLine());
}
}
}
}
Then change your ConsoleServerApp to a Winforms application so that it can display the notification whenever the windows service sends it a message:
public Form1()
{
InitializeComponent();
StartServer();
Task.Delay(_threadJoinTimeout).Wait();
}
public void DisplayMessage()
{
this.notifyIcon1.BalloonTipIcon = ToolTipIcon.Info;
this.notifyIcon1.BalloonTipText = "Welcomd!";
this.notifyIcon1.BalloonTipTitle = "Title";
this.notifyIcon1.ShowBalloonTip(2000);
}
void StartServer()
{
Task.Factory.StartNew(() =>
{
var server = new NamedPipeServerStream("PipesOfPiece");
server.WaitForConnection();
StreamReader reader = new StreamReader(server);
while (true)
{
var line = reader.ReadLine();
DisplayMessage();
}
});
}
Then put the ConsoleClientApp into your Windows Service.
For details on the pipe please see Example of Named Pipes
For the System Tray application please see http://www.tutorialspanel.com/create-system-tray-icon-windows-forms-application-using-c-vb-net/#:~:text=Below%20is%20an%20example%20of%20how%20to%20create,Step%203.%20Add%20an%20icon%20to%20the%20NotifyIcon
Here are tips on using the TopShelf NuGet package which allows you to debug your Windows Service as a Console Application: https://www.codeproject.com/Articles/881511/SignalR-with-Self-hosted-Windows-Service
I have a webservices's project. I'm trying to write a log per each method using StreamWriter, in my local machine everything is working fine.
Something like this:
static StreamWriter sw;
try{
if (File.Exists(Directorio + FILE_NAME))
{
sw = File.AppendText(Directorio + FILE_NAME);
}
else
{
sw = File.CreateText(Directorio + FILE_NAME);
sw.WriteLine("---LOG ");
}
sw.WriteLine(Date);
sw.WriteLine(Header);
sw.WriteLine();
sw.Close();//*/
}catch(Exception){}
But when is uploaded to the server sometimes it throws an error that can't write because the file is in use. But I close it every time and I thought that with the try catch should ignore that part and continue with the method, because I don't want to affect the process of each method.
I know that is little information, and I can't reproduce my problem here but hope that someone who had an error like this could give me a hint.
Web servers typically handle multiple requests at once. The occasional error is most likely due to one request trying to log while another request is already logging, and not yet done.
If you wish do use your own logging framework, you will need to coordinate writes to the file.
You could also use one of the exceptional, open-source logging frameworks such as NLog.
This could be due to multiple requests coming to web server and one request trying to write to this log file while other is trying to open. possible fix could be thread synchronization, which is not good as it would significantly degrade the performance of web service. Alternatively I'd recommend using nLog (http://nlog-project.org/), used in several projects without any issues.
I am writing a messaging app in C# that runs on a shared file server on a network. The program works by multiple users running the program which accesses a file that is shared between the multiple computers. Hence, I need to use the StreamReader/StreamWriter to access the file with multiple programs at once (EDIT: I now know this isn't a good way to do it, but it's what I needed at the time). So how may I access a single file with multiple programs without getting errors about the file being in use?
I think your approach will lead to problems in the future. I'd consider leveraging Redis pub/sub if I were you.
But, since you asked... (I wrote a blog post on this: http://procbits.com/2011/02/18/streamwriter-share-read-access-in-another-process/ )
Generator of chat data:
var fs = File.Open(#"C:\messages.txt", FileMode.Append, FileAccess.Write, FileShare.Read);
var sw = new StreamWriter(fs);
sw.AutoFlush = true;
Somewhere else in your app or another app...
Readers of chat data:
var fs = File.Open(#"C:\messages.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
var sr = new StreamReader(fs);
If you need single file where multiple users/programs/entites.. shoud read/write without disturbing each other, I would suggest to consider (among other solutions) an use of Sqlite like a simple DB backend. No installation or service setup needed. Just use C# dlls of it and, basically, according to your requests, you will get what you need.
One user writes in the db file (INSERT) another can read (SELECT) from it.
I think you should think twice about using a text file as a means of a communication peer.
It's like asking for trouble.
Please take a look at using a P2P solution instead:
Peer Channel Chat
A simple peer to peer chat application using WCF netPeerTcpBinding
That will give you a much more fitting architecture for your requirements.