Hướng dẫn gửi fax trong C# sử dụng FAXCOMEXLib và các lỗi thường gặp

Môi trường chạy dịch vụ: Windows Server 2019, công cụ phát triển: Visual Studio 2022.

1. Cấu hình dịch vụ Fax

Kích hoạt dịch vụ Fax trên Windows Server như hình minh họa dưới đây:
Cấu hình Fax Server

2. Thêm tham chiếu COM

Trong project, vào Project PropertiesAdd COM Reference, chọn Microsoft Fax Service. Lưu ý quan trọng: không chọn các phiên bản bắt đầu bằng chữ "f" (ví dụ: FaxComEx...). Chỉ sử dụng phiên bản có tiền tố "M" (Microsoft Fax Service).

3. Triển khai gửi fax

Khởi tạo lớp gửi fax, kết nối tới máy fax cục bộ (tham số rỗng):
public class FaxSender
{
    private FaxServer faxServer;
    private FaxDocument faxDoc;
    private static readonly ILogger logger = LogManager.GetLogger();

    public FaxSender()
    {
        try
        {
            faxServer = new FaxServer();
            faxServer.Connect("");
            RegisterServerEvents();
        }
        catch (Exception ex)
        {
            logger.Error(ex, "Lỗi kết nối tới Fax Server.");
        }
    }
}
Đăng ký các sự kiện theo dõi trạng thái gửi fax:
private void RegisterServerEvents()
{
    faxServer.OnOutgoingJobAdded += HandleJobAdded;
    faxServer.OnOutgoingJobChanged += HandleJobChanged;
    faxServer.OnOutgoingJobRemoved += HandleJobRemoved;

    var eventFlags = FAX_SERVER_EVENTS_TYPE_ENUM.fsetFXSSVC_ENDED |
                     FAX_SERVER_EVENTS_TYPE_ENUM.fsetOUT_QUEUE |
                     FAX_SERVER_EVENTS_TYPE_ENUM.fsetOUT_ARCHIVE |
                     FAX_SERVER_EVENTS_TYPE_ENUM.fsetQUEUE_STATE |
                     FAX_SERVER_EVENTS_TYPE_ENUM.fsetACTIVITY |
                     FAX_SERVER_EVENTS_TYPE_ENUM.fsetDEVICE_STATUS;

    faxServer.ListenToServerEvents(eventFlags);
}

private static void HandleJobAdded(FaxServer server, string jobId)
{
    logger.Info("Sự kiện OnOutgoingJobAdded: Một fax mới đã được thêm vào hàng đợi.");
}

private static void HandleJobChanged(FaxServer server, string jobId, FaxJobStatus status)
{
    logger.Info("Sự kiện OnOutgoingJobChanged: Trạng thái fax thay đổi.");
    server.Folders.OutgoingQueue.Refresh();
    LogJobStatus(status);
}

private static void HandleJobRemoved(FaxServer server, string jobId)
{
    logger.Info("Sự kiện OnOutgoingJobRemoved: Fax đã bị xóa khỏi hàng đợi.");
}

private static void LogJobStatus(FaxJobStatus status)
{
    if (status.ExtendedStatusCode == FAX_JOB_EXTENDED_STATUS_ENUM.fjesDIALING)
    {
        logger.Info("Đang quay số...");
    }
    else if (status.ExtendedStatusCode == FAX_JOB_EXTENDED_STATUS_ENUM.fjesTRANSMITTING)
    {
        logger.Info("Đang gửi fax...");
    }
    else if (status.Status == FAX_JOB_STATUS_ENUM.fjsCOMPLETED &&
             status.ExtendedStatusCode == FAX_JOB_EXTENDED_STATUS_ENUM.fjesCALL_COMPLETED)
    {
        logger.Info("Fax đã được gửi thành công.");
    }
}

4. Phương thức gửi fax chính

/// <summary>
/// Gửi fax tới máy chủ fax.
/// </summary>
/// <param name="filePath">Đường dẫn file cần gửi (txt, tif, pdf...).</param>
/// <param name="faxInfo">Đối tượng chứa thông tin người gửi và số nhận.</param>
/// <param name="subject">Tiêu đề fax (tùy chọn).</param>
/// <param name="docName">Tên tài liệu (tùy chọn).</param>
public void SendFax(string filePath, FaxMessage faxInfo, string subject = null, string docName = null)
{
    try
    {
        logger.Debug("Bắt đầu cấu hình tài liệu fax.");
        SetupFaxDocument(subject, docName, filePath, faxInfo.Sender, faxInfo.Recipient);
        logger.Debug("Kết thúc cấu hình, bắt đầu gửi fax.");
        var result = faxDoc.Submit(faxServer.ServerName);
        logger.Debug($"Kết quả gửi: {JsonConvert.SerializeObject(result)}");
        faxDoc = null;
    }
    catch (Exception ex)
    {
        logger.Error(ex, $"Lỗi gửi fax: {ex.Message}");
    }
}

private void SetupFaxDocument(string subject, string docName, string filePath, string sender, string recipient)
{
    faxDoc = new FaxDocument
    {
        Priority = FAX_PRIORITY_TYPE_ENUM.fptLOW,
        ReceiptType = FAX_RECEIPT_TYPE_ENUM.frtNONE,
        AttachFaxToReceipt = true,
        Body = filePath,
        Subject = subject ?? Path.GetFileNameWithoutExtension(filePath),
        DocumentName = docName ?? Path.GetFileName(filePath)
    };

    faxDoc.Sender.Name = sender;
    faxDoc.Sender.Company = "";
    faxDoc.Recipients.Add(recipient);
}

Lưu ý quan trọng về Priority

Khi sử dụng FAX_PRIORITY_TYPE_ENUM.fptHIGH trong project chạy dưới dạng Windows Service, việc in file PDF có thể gây lỗi:
  • System.IO.FileLoadException: Operation failed
  • System.UnauthorizedAccessException: Access denied
Do đó, nên sử dụng fptLOW hoặc thử nghiệm với fptNORMAL.

Xử lý file PDF

Để gửi file PDF, máy tính bắt buộc phải cài đặt một trình đọc PDF (ví dụ: Adobe Acrobat Reader hoặc Foxit Reader). Nếu không, bạn sẽ gặp lỗi:
System.Runtime.InteropServices.COMException (0x80070102): Operation failed.
Tác giả đã thử nghiệm thành công với Adobe Acrobat Reader và Foxit Reader. Đồng thời, priority phải là fptLOW.

Các định dạng file khác

Project đã thử nghiệm thành công với file .txt.tif. Các định dạng khác chưa được kiểm tra.

Tham khảo thêm

Thẻ: C# FAXCOMEXLib Fax Server Windows Server COM Reference

Đăng vào ngày 1 tháng 7 lúc 00:24