2013-06-26 36 views
1

我繼承了一個應用程序,該應用程序使用Microsoft Web ReportViewer在本地運行小型報告。我們的應用程序允許您通過單擊將用戶路由到允許他們以PDF格式下載報告的URL的特定按鈕來「預覽/打印」報告。我們最近收到了將這些PDF保存到數據庫中的文檔表的要求。我已經能夠在localhost上成功運行了;然而,當我發佈應用程序到我們的IIS服務器,我收到以下錯誤:本地ReportViewer在不必要的數據庫登錄時失敗

System.Data.SqlClient.SqlException: Login failed for user 'Domain\Servername$'. 

我查看了所有的網站,我能找到涉及這個錯誤(包括this one) - 最點添加服務器帳戶到SQL數據庫;然而,這不應該成爲一個問題,因爲預覽/打印文檔的按鈕仍然可以正常工作,並在應用程序發佈時按預期工作,並且所有數據都保存在本地對象中,該對象先前已從數據庫中提取(下面的模型參數)。按鈕和自動生成功能使用相同的兩種方法創建PDF文檔(請參見下文)。

下面是一些代碼:

public static byte[] CreatePDFDocument(DocumentTemplateType template, Request model) 
    { 
     Warning[] warnings; 
     string[] streamIds; 
     string mimeType = string.Empty; 
     string encoding = string.Empty; 
     string extension = string.Empty; 

     ReportViewer viewer = new ReportViewer(); 

     viewer.ProcessingMode = ProcessingMode.Local; 
     viewer.LocalReport.ReportEmbeddedResource = "Xxx.Xxx.Bll.ReportViewerRDLCs." + template.RdlcFilename; 

     switch ((DocumentType)template.DocumentTypeId) 
     { 
      case eDocumentType.Report1: 
       viewer.LocalReport.SetParameters(GetForm1Parameters(model)); 
       break; 
      /** 
      * Several other reports are in this switch. All reports have the 
      * same issue - all but one are removed for brevity. 
      */ 
     } 

     byte[] bytes = viewer.LocalReport.Render("PDF", null, out mimeType, out encoding, out extension, out streamIds, out warnings); 

     return bytes; 

     //return new byte[5] {5,6,7,8,9}; - used for troubleshooting. 
    } 


    public static List<ReportParameter> GetReport1Parameters(Request model) 
    { 
     List<ReportParameter> rptParams = new List<ReportParameter>(); 

     //Start comment 
     rptParams.Add(new ReportParameter("EmployeeFullName", string.Format("{0:NN}", model.Employee))); 
     rptParams.Add(new ReportParameter("EmployeePhoneNumber", string.Format("{0:(###) ###-####}", Convert.ToInt64(model.Employee.PhoneNumber)))); 
     rptParams.Add(new ReportParameter("HrchyShortDesc", model.Employee.HrchyShortDesc)); 
     rptParams.Add(new ReportParameter("RequestDate", model.RequestDate.ToShortDateString())); 
     rptParams.Add(new ReportParameter("RequestRequested", model.RequestRequestType)); 
     rptParams.Add(new ReportParameter("ReasonForRequest", model.RequestRequestReason)); 
     rptParams.Add(new ReportParameter("LogNumber", model.CaseId)); 

     if (!string.IsNullOrWhiteSpace(model.TimeSensitiveReason)) rptParams.Add(new ReportParameter("TimeSensitiveReason", model.TimeSensitiveReason)); 

     var lastAction = model.LastActionOfType(WorkflowStateActionType.EmployeeConfirmation); 
     if (lastAction != null) 
     { 
      rptParams.Add(new ReportParameter("TodaysDate", lastAction.ActionDate.ToShortDateString())); 
      rptParams.Add(new ReportParameter("EmpConfirmed", "true")); 
     } 
     else rptParams.Add(new ReportParameter("TodaysDate", DateTime.Now.ToShortDateString())); 
     //end comment 
     return rptParams; 
    } 

通過大量的評論和退出,並推到我們的服務器,我已經推導出以下幾點:

  1. 從我所知道的,錯誤調用GetReport1Parameters時發生。在上面的代碼中,我包含了一個開始和結束註釋 - 我已經註釋掉了它們之間的所有內容,只留下列表初始化和返回語句(空列表),但仍然收到錯誤。
  2. 我已經註釋掉了對GetReport1Parameters的調用,並返回了一個無意義的字節數組,並且沒有收到異常。
  3. 所有的功能在localhost上都能正常工作,當我逐步完成這些功能時,所有的變量都顯得很正常。

事情我已經嘗試做亡羊補牢: 1.從app.config中刪除的連接字符串,使應用程序去web.config文件以獲得正確的字符串(即使他們是一樣的)。 2.評論不同部分的代碼以確定問題區域。 3.嘗試調用GetReport1Parameters方法並返回null,導致空引用異常。 4.嘗試使用空參數列表調用GetReport1Parameters,導致上述錯誤。 5.嘗試運行報告沒有參數(甚至沒有空白列表),得到ReportProcessingException缺少參數。

一些額外的信息:

  • 我們使用服務帳戶在web.config中使用冒充身份的申請。該行在localhost上被註釋掉,但在IIS上運行。
  • 所有其他數據庫交互都能正常工作。
  • 我們所有的數據庫交互操作都是使用LINQ to SQL完成的 - 模型是一個基於數據庫表的對象,具有一些動態計算的附加信息。

我希望的結果是自動生成的文檔和預覽/打印文檔都可以工作。我有一種感覺,這可能是我忽略的簡單事情,但我今天已經花了幾個小時試圖解決這個問題。

我想不出任何其他相關信息,但如果您有任何疑問,我會很樂意回答。

編輯:其他試圖找到解決方案:

  • 嘗試設置LINQ延遲加載等於假。這造成了比解決問題更多的問題。

  • 實施了IReportServerCredentials,併爲ReportViewer的ServerReport.ReportServerCredentials分配了正確的數據庫憑證。

  • 將所有相關的報告參數分配給Dictionary,然後在每個對象上調用.ToString()以確保它從數據庫中被拉出。然後將字典中的字符串分配給報告參數,以便ReportViewer應該從字符串池接收數據,而不是從數據庫中提取數據。

  • +0

    你是否附加了一個調試器,並在返回之前查看rptParams? – Chris

    +0

    我還沒有嘗試遠程調試,但是當我在本地主機上調試時,所有參數似乎都正確返回。正如我在上面的回答中所提到的,傳遞到創建報告參數的方法的對象在打印/預覽選項和自動生成選項上都是相同的。 – floppsb

    +0

    這是否在本地主機上或僅在部署時失敗? – Chris

    回答

    0

    即使您正在使用一個ObjectDataSource將數據傳遞到您的報告,報表查看器仍然會調用Select方法,這反過來又可能導致發生數據庫訪問。因此,即使看起來登錄是不必要的,您仍然需要深入瞭解與ObjectDataSource一起提供的數據訪問方法,以便確定。

    你正在被通過報表查看器2010年的錯誤是描述下面的Microsoft連接的文章中導致錯誤:

    ReportViewer.LocalReport.Render and ReportViewer.LocalReport.SetParameters changes ImpersonationLevel to None

    雖然文章提到這個問題應該是固定在Service Pack 1,似乎並非如此。我還沒有驗證這個問題是否在Report Viewer 2012中得到了解決。

    我通過更改數據訪問層來比較當前身份與我的HttpContext中的身份並根據需要使用以下代碼片段恢復它:

    System.Security.Principal.IIdentity id = System.Web.HttpContext.Current.User.Identity 
    if (id.Name != System.Security.Principal.WindowsIdentity.GetCurrent().Name) 
    { 
        context = (id as System.Security.Principal.WindowsIdentity).Impersonate() 
    } 
    

    我在連接到數據庫之前就這樣做,並在連接打開後立即撤消它。

    我對此解決方案並不興奮,主要是因爲現在我的數據訪問層正在引用UI層(System.Web)。

    相關問題