在C#中使用WebRequest时为Microsoft Report Server提供凭据

问题描述

我想使用C#代码从我们的Microsoft Report Server下载PDF报告。我不知道为什么,但是我做错了。我总是收到一条错误消息,提示身份验证失败(HTTP 401)。

public static async Task<Stream> DownloadWebDocument(string url) {
    if (string.IsNullOrEmpty(url))
        throw new ArgumentNullException(nameof(url));

    WebRequest request = WebRequest.Create(url);

    request.Method = "GET";
    request.AuthenticationLevel = System.Net.S@R_404[email protected];
    request.Credentials = new NetworkCredential("MyUsername","MyPassword","MyDomain");

    //request.Headers.Add("Authorization",$"Basic {Convert.ToBase64String(System.Text.Encoding.Default.GetBytes("MyUsername:MyPassword"))}");

    try {
        using WebResponse response = await request.GetResponseAsync();

        return response.GetResponseStream();
    } catch (Exception ex) {
        var a = ex.Message;

        throw;
    }

    //return await DownloadWebDocument(uri);
}

代码始终会遇到异常。但是为什么呢?

PS:

根据要求,这是堆栈跟踪。没有内部异常。

   bei System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
   bei System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar,Func`2 endFunction,Action`1 endAction,Task`1 promise,Boolean requiresSynchronization)
--- Ende der Stapelüberwachung vom vorhergehenden Ort,an dem die Ausnahme ausgelöst wurde ---
   bei System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   bei System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   bei DE.ZA.TrailerLoadingAssistant.Web.Code.WebHelper.<DownloadWebDocument>d__0.MoveNext() in C:\Users\Reichelt\source\repos\DE.ZA.TrailerLoading\DE.ZA.TrailerLoadingAssistant.Web\Code\WebHelper.cs:Zeile 28.

解决方法

实际上,我使用其他方法将报告呈现为PDF文档:

    public static byte[] DownloadAsPDF(string ReportServer,string ReportPath)
    {
        ReportViewer ReportViewer1 = new ReportViewer();
        ReportViewer1.ServerReport.ReportServerCredentials = new 
CustomReportCredentials("MyUsername","MyPassword","MyDomain");
        ReportViewer1.ProcessingMode = 
Microsoft.Reporting.WebForms.ProcessingMode.Remote;
        ReportViewer1.ServerReport.ReportServerUrl = new Uri(ReportServer);
        ReportViewer1.ServerReport.ReportPath = ReportPath;

       
        byte[] bytes = ReportViewer1.ServerReport.Render("PDF");

        return bytes;
    }

    public class CustomReportCredentials : 
    Microsoft.Reporting.WebForms.IReportServerCredentials
    {
        // local variable for network credential.    
        private string _UserName;
        private string _PassWord;
        private string _DomainName;
        public CustomReportCredentials(string UserName,string PassWord,string DomainName)
        {
            _UserName = UserName;
            _PassWord = PassWord;
            _DomainName = DomainName;
        }

        public System.Security.Principal.WindowsIdentity ImpersonationUser
        {
            get
            {
                return null;  // not use ImpersonationUser        
            }
        }

        public ICredentials NetworkCredentials
        {
            get
            {
                // use NetworkCredentials            
                return new NetworkCredential(_UserName,_PassWord,_DomainName);
            }
        }

        public bool GetFormsCredentials(out Cookie authCookie,out string 
user,out string password,out string authority)
        {
            authCookie = null;
            user = password = authority = null;
            return false;
        }
    }
,

我意识到,如果我使用request.Credentials = CredentialCache.DefaultCredentials,它就可以工作。因此,我的凭据肯定有问题。但这绝对不是错字。

我遇到了这个问题,似乎有人在更改网络权限。一个星期使用凭据将起作用,然后第二个星期使用DefaultCredentials将起作用。真的很奇怪,因此如果服务帐户失败,我会尝试/捕获并使用DefaultCredentials,请参见代码注释:

public class SRSHelper
{
    private ReportingService2005 rsServ;
    private ReportingExecution2005 rsExec = new ReportingExecution2005();
    private ReportParameter[] reportParameters;
    private ExecutionInfo execInfo = null;

    public SRSHelper(string reportUserName,string decryptedPassword,string reportDomain,string reportServerURL)
     {
        rsServ = new ReportingService2005(reportServerURL);
        rsExec.Url = reportServerURL + @"ReportExecution2005.asmx";

        System.Net.NetworkCredential creds = new System.Net.NetworkCredential();
        creds.UserName = reportUserName;
        creds.Password = decryptedPassword;
        creds.Domain = reportDomain;
        rsExec.Credentials = creds;
        rsServ.Credentials = creds;
     }

    public ReportParameter[] GetSRSReportParameters(string reportName)
    {
        string report = "/Reporting/" + reportName;
        bool forRendering = false;
        string historyID = null;
        ParameterValue[] values = null;
        DataSourceCredentials[] credentials = null;

        try
        {
            return rsServ.GetReportParameters(report,historyID,forRendering,values,credentials);
        }
        catch
        {
            //If the Service Account credentials fail to work - try the users credentials - XYZ vendor regularly change things around or the network fails or for some reason beyond our control we have to change the settings.
            rsExec.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
            rsServ.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
            return rsServ.GetReportParameters(report,credentials);
        }
            
    }