2008-09-23 22 views
6

Tôi đã tạo một dịch vụ web trong .net 2.0, C#. Tôi cần phải đăng nhập một số thông tin vào một tập tin bất cứ khi nào các phương thức khác nhau được gọi bởi các máy khách dịch vụ web.Sự cố khi ghi vào một tệp trong dịch vụ Web trong .NET

Sự cố xảy ra khi một quá trình người dùng đang ghi vào một tệp và một quy trình khác cố gắng ghi vào tệp đó. Tôi nhận được lỗi sau:

The process cannot access the file because it is being used by another process.

Các giải pháp mà tôi đã cố gắng triển khai trong C# và không thành công như sau.

  1. Lớp singleton được triển khai có chứa mã viết vào tệp.
  2. Đã sử dụng câu lệnh khóa để bọc mã ghi vào tệp.
  3. Tôi cũng đã cố gắng sử dụng logger logger nguồn mở nhưng nó cũng không phải là một giải pháp hoàn hảo.
  4. Tôi biết về việc đăng nhập vào trình ghi sự kiện hệ thống, nhưng tôi không có lựa chọn đó.

Tôi muốn biết liệu có tồn tại một giải pháp hoàn hảo và hoàn chỉnh cho vấn đề như vậy không?

Trả lời

10

Khóa có thể không thành công vì dịch vụ web của bạn đang được chạy bởi nhiều quy trình công nhân. Bạn có thể bảo vệ truy cập với một mutex được đặt tên, được chia sẻ trên các quy trình, không giống như các ổ khóa bạn nhận được bằng cách sử dụng lock(someobject) {...}:

Mutex lock = new Mutex("mymutex", false); 

lock.WaitOne(); 

// access file 

lock.ReleaseMutex(); 
+0

Mutex lockobj = new Mutex (sai, "mymutex"); sẽ biên dịch –

+0

Bạn nên thử mở một Mutex hiện có với tên đó trước tiên trước khi tạo. Nếu không, dòng "Mutex mới (...)" có thể ném một ngoại lệ. Tôi cũng khuyên bạn nên sử dụng khối try/catch/finally, di chuyển lệnh Phát hành vào khối cuối cùng và chỉ phát hành nó nếu bạn thực sự có khóa. –

0

Có thể viết một dòng "xếp hàng" để ghi vào tệp, vì vậy khi bạn cố gắng ghi vào tệp, nó sẽ kiểm tra xem tệp có bị khóa không, nếu có - nó vẫn đang chờ, nếu nó không không được khóa - sau đó viết cho nó.

0

Bạn có thể đẩy kết quả vào hàng đợi MSMQ và có dịch vụ cửa sổ chọn các mục ra khỏi hàng đợi và đăng nhập chúng. Hơi nặng một chút, nhưng nó sẽ hoạt động.

0

Joel và charles. Nó thật nhanh! :)

Joel: Khi bạn nói "hàng đợi" bạn có nghĩa là tạo một chuỗi riêng biệt chạy trong vòng lặp để tiếp tục kiểm tra hàng đợi cũng như ghi vào một tệp khi nó không bị khóa không?

Charles: Tôi biết về MSMQ và cửa sổ kết hợp dịch vụ, nhưng như tôi đã nói tôi không có lựa chọn nào khác hơn là viết vào một tập tin từ bên trong dịch vụ web :)

nhờ pradeep_tp

0

Rắc rối với tất cả tiếp cận đã cố gắng cho đến nay là nhiều luồng có thể nhập mã. Đó là nhiều chủ đề cố gắng để có được và sử dụng xử lý tập tin - do đó các lỗi - bạn cần một chủ đề duy nhất bên ngoài của các chủ đề công nhân để làm công việc - với một xử lý tập tin duy nhất được tổ chức mở.

Có lẽ điều dễ nhất để làm là tạo chuỗi trong khi bắt đầu ứng dụng trong Global.asax và có lắng nghe hàng đợi trong bộ nhớ được đồng bộ hóa (System.Collections.Generics.Queue). Để chuỗi mở và sở hữu toàn bộ thời gian xử lý tệp, chỉ chuỗi đó có thể ghi vào tệp.

Yêu cầu của khách hàng trong ASP sẽ khóa hàng đợi trong giây lát, đẩy thông điệp ghi nhật ký mới lên hàng đợi, sau đó mở khóa.

Chuỗi nhật ký sẽ thăm dò hàng đợi định kỳ cho thư mới - khi thư đến hàng đợi, chuỗi sẽ đọc và gửi dữ liệu vào tệp.

1

Bạn không nói cách dịch vụ web của bạn được lưu trữ, vì vậy tôi sẽ giả định nó trong IIS. Tôi không nghĩ rằng tập tin nên được truy cập bởi nhiều quy trình trừ khi dịch vụ của bạn chạy trong nhiều hồ bơi ứng dụng. Tuy nhiên, tôi đoán bạn có thể nhận được lỗi này khi nhiều chủ đề trong một quá trình đang cố gắng để viết.

Tôi nghĩ rằng tôi muốn đi cho giải pháp bạn đề xuất bản thân, Pradeep, xây dựng một đối tượng duy nhất thực hiện tất cả văn bản cho tệp nhật ký. Bên trong đối tượng đó tôi sẽ có một Hàng đợi để tất cả dữ liệu được ghi lại được ghi vào. Tôi muốn có một chủ đề riêng biệt đọc từ hàng đợi này và ghi vào tệp nhật ký. Trong một môi trường lưu trữ gộp luồng như IIS, nó có vẻ không quá đẹp để tạo ra một luồng khác, nhưng nó chỉ là một chuỗi ... Hãy nhớ rằng hàng đợi trong bộ nhớ sẽ không tồn tại trong các lần reset IIS; bạn có thể mất một số mục nhập là "trên máy bay" khi quá trình IIS bị hỏng.

Các lựa chọn thay thế khác chắc chắn bao gồm sử dụng một quy trình riêng biệt (chẳng hạn như Dịch vụ) để ghi vào tệp, nhưng có thêm chi phí triển khai và chi phí IPC. Nếu điều đó không hiệu quả với bạn, hãy đi với singleton.

0

Để biết những gì tôi đang cố gắng để làm trong mã của tôi, sau là lớp singletone tôi đã thực hiện trong C#

public class kín FileWriteTest {

private static volatile FileWriteTest instance; 

private static object syncRoot = new Object(); 

private static Queue logMessages = new Queue(); 

private static ErrorLogger oNetLogger = new ErrorLogger(); 

private FileWriteTest() { } 

public static FileWriteTest Instance 
{ 
    get 
    { 
     if (instance == null) 
     { 
      lock (syncRoot) 
      { 
       if (instance == null) 
       { 
        instance = new FileWriteTest(); 
        Thread MyThread = new Thread(new ThreadStart(StartCollectingLogs)); 
        MyThread.Start(); 

       } 
      } 
     } 

     return instance; 
    } 
} 

private static void StartCollectingLogs() 
{ 

    //Infinite loop 
    while (true) 
    { 
     cdoLogMessage objMessage = new cdoLogMessage(); 
     if (logMessages.Count != 0) 
     { 
      objMessage = (cdoLogMessage)logMessages.Dequeue(); 
      oNetLogger.WriteLog(objMessage.LogText, objMessage.SeverityLevel); 

     } 
    } 
} 

public void WriteLog(string logText, SeverityLevel errorSeverity) 
{ 
    cdoLogMessage objMessage = new cdoLogMessage(); 
    objMessage.LogText = logText; 
    objMessage.SeverityLevel = errorSeverity; 
    logMessages.Enqueue(objMessage); 

} 

}

Khi tôi chạy mã này trong chế độ gỡ lỗi (mô phỏng chỉ một người dùng truy cập), tôi nhận được lỗi "ngăn xếp tràn" ở dòng nơi hàng đợi được dequeued.

Lưu ý: Trong mã trên ErrorLogger là một lớp có mã để ghi vào Tệp. objMessage là một lớp thực thể để mang thông điệp tường trình.

+0

Tại sao sử dụng dễ bay hơi, nếu bạn không biết cách sử dụng? ; P – leppie

0

Ngoài ra, bạn có thể muốn làm lỗi đăng nhập vào cơ sở dữ liệu (nếu bạn đang sử dụng một)

0

Koth,

tôi đã thực hiện khóa Mutex, trong đó đã loại bỏ các lỗi "stack overflow". Tôi chưa phải làm thử nghiệm tải trước khi tôi có thể kết luận liệu nó có hoạt động tốt trong mọi trường hợp hay không.

Tôi đã đọc về bộ đệm Mutex ở một trong các trang web, cho biết Mutex ảnh hưởng đến hiệu suất. Tôi muốn biết một điều với việc đặt khóa thông qua Mutex.

Giả sử quy trình người dùng1 đang ghi vào một tệp và đồng thời Quy trình người dùng2 cố gắng ghi vào cùng một tệp. Kể từ khi Process1 đã đặt một khóa trên khối mã, sẽ Process2 sẽ tiếp tục cố gắng hoặc chỉ chết sau khi attempet đầu tiên chính nó.?

nhờ pradeep_tp

+0

Process2 sẽ đợi cho đến khi Process1 kết thúc. Để giảm thiểu điều này, hãy làm càng nhiều càng tốt bên ngoài khóa. – Khoth

0

Nó sẽ đợi cho đến khi mutex được phát hành ....

0

Joel: When you say "queue line" do you mean creating a separate thread that runs in a loop to keep checking the queue as well as write to a file when it is not locked?

Yeah, đó là về cơ bản những gì tôi đã suy nghĩ. Có một chuỗi khác có vòng lặp while cho đến khi nó có thể truy cập vào tệp và lưu, sau đó kết thúc.

Nhưng bạn sẽ phải thực hiện theo cách mà chuỗi đầu tiên bắt đầu tìm kiếm được truy cập trước tiên. Đó là lý do tại sao tôi nói hàng đợi.

Các vấn đề liên quan