Crystal Report Viewer(Asp.NET) 無法Download PrintControl.cab問題

Crystal Report Viewer(Asp.NET) 無法Download PrintControl.cab問題

前言

依上篇「建立共用的Asp.NET Crystal Report 2008 Viewer程式!」中,因為印表的方式是使用ActiveX方式,所以會Download PrintControl ActiveX到Client去印表! 但是有些Report可以Download, 有些卻不行!

研究

發現不可以download的情形是在download的畫面上會出現「發行者:發行者不明」,按下安裝後,就動也不動。

而可以download的情形在download的畫面上則會出現「發行者:Business Objects Americas」,如下圖!

發行者不明

正確的發行者

應該是URL有問題吧!

看一下那個printControl.cab之前居然有/,如下圖!

CRViewer.aspx?aZ8JMRWR2YxLwZ327aUlK9uVqPC4wivWDSowQ8mCmurrCyLSkxIGXTfplnHRq/9vwis0MsC7A/gb22QQGj2emqFCRcRwC03e9lrOCFRnba@@@VmROgtCXeRTzJ89WZ2/ayY3XFNFJETdvgeLYbMsS8wVx8dhkKW6cnvjomGVPY/../aspnet_client/system_web/2_0_50727/crystalreportviewers12/ActiveXControls/PrintControl.cab

url

所以就修正StringHelper的加解密Function,將/改以3個$替換後,就可以正常Download了!


//因為要列印時,前面不能有/會造成download PrintControl.cab錯誤
 return Convert.ToBase64String(bytOut).Replace("+", "@@@").Replace(@"/", "$$$");

byte[] bytIn = Convert.FromBase64String(encryptedString.Replace("@@@", "+").Replace("$$$", @"/"));

完整的function如下,


using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Security.Cryptography;
using System.Collections.Specialized;
using System.Text;
using System.IO;

/// <summary>
/// 加解密字串
/// </summary>
/// <remarks>
/// 改自網路,加入自定Key值加解密及錯誤處理
/// </remarks>
public class StringHelpers
{
    public const char QUERY_STRING_DELIMITER = '&';

    private static RijndaelManaged _cryptoProvider;
    //128 bit encyption: DO NOT CHANGE
    private static readonly byte[] Key = { 18, 19, 8, 24, 8, 22, 2, 25, 17, 5, 11, 9, 13, 15, 06, 9 };
    private static readonly byte[] IV = { 14, 2, 16, 7, 5, 9, 33, 23, 23, 47, 16, 12, 1, 32, 25, 9 };
    static StringHelpers()
    {
        _cryptoProvider = new RijndaelManaged();
        _cryptoProvider.Mode = CipherMode.CBC;
        _cryptoProvider.Padding = PaddingMode.PKCS7;
    }

    public static string Encrypt(string unencryptedString)
    {
        return Encrypt(unencryptedString, string.Empty);
    }

    public static string Encrypt(string unencryptedString, string myKey)
    {

        //byte[] bytIn = ASCIIEncoding.ASCII.GetBytes(unencryptedString);
        //如果內容有unicode的話,要用utf8編碼
        byte[] bytIn = UTF8Encoding.UTF8.GetBytes(unencryptedString);
        byte[] bytKey;
        if(string.IsNullOrEmpty(myKey)){
            bytKey = Key;
        }else{
            bytKey = ASCIIEncoding.ASCII.GetBytes(myKey);
            Array.Resize(ref bytKey, 16);
        }
        // Create a MemoryStream
        MemoryStream ms = new MemoryStream();
        // Create Crypto Stream that encrypts a stream
        CryptoStream cs = new CryptoStream(ms, _cryptoProvider.CreateEncryptor(bytKey, IV), CryptoStreamMode.Write);
        // Write content into MemoryStream
        cs.Write(bytIn, 0, bytIn.Length);
        cs.FlushFinalBlock();
        byte[] bytOut = ms.ToArray();
        //因為url不能吃+所以要轉成@@@
        //因為要列印時,前面不能有/會造成download PrintControl.cab錯誤
        return Convert.ToBase64String(bytOut).Replace("+", "@@@").Replace(@"/", "$$$");
    }

    public static string Decrypt(string encryptedString)
    {
        return Decrypt(encryptedString, string.Empty);
    }

    public static string Decrypt(string encryptedString, string myKey)
    {
        if (encryptedString.Trim().Length != 0)
        {
            //如果有人改加密字串的話,解就會發生錯誤,所以錯誤就回傳空字串
            try
            {
                // Convert from Base64 to binary 在解開前要先將@@@轉成+,將$$$轉成/
                byte[] bytIn = Convert.FromBase64String(encryptedString.Replace("@@@", "+").Replace("$$$", @"/"));
                byte[] bytKey;
                if(string.IsNullOrEmpty(myKey)){
                    bytKey = Key;
                }else{
                    bytKey = ASCIIEncoding.ASCII.GetBytes(myKey);
                    Array.Resize(ref bytKey, 16);
                }
                // Create a MemoryStream
                MemoryStream ms = new MemoryStream(bytIn, 0, bytIn.Length);
                // Create a CryptoStream that decrypts the data
                CryptoStream cs = new CryptoStream(ms, _cryptoProvider.CreateDecryptor(bytKey, IV), CryptoStreamMode.Read);

                // Read the Crypto Stream
                StreamReader sr = new StreamReader(cs);
                return sr.ReadToEnd();
            }
            catch
            {
                return "";
            }
        }
        else
        {
            return "";
        }
    }

    public static NameValueCollection DecryptQueryString(string queryString)
    {
        return DecryptQueryString(queryString, string.Empty);
    }

    public static NameValueCollection DecryptQueryString(string queryString, string myKey)
    {
        if (queryString.Length != 0)
        {
            //Decode the string
            string decodedQueryString = HttpUtility.UrlDecode(queryString);
            //Decrypt the string
            string decryptedQueryString = StringHelpers.Decrypt(decodedQueryString, myKey );
            //Now split the string based on each parameter
            string[] actionQueryString = decryptedQueryString.Split(new char[] { QUERY_STRING_DELIMITER });
            NameValueCollection newQueryString = new NameValueCollection();
            //loop around for each name value pair.
            for (int index = 0; index < actionQueryString.Length; index++)
            {
                string[] queryStringItem = actionQueryString[index].Split(new char[] { '=' });
                if(queryStringItem.Length > 1)
                    newQueryString.Add(queryStringItem[0], queryStringItem[1]);
            }
            return newQueryString;
        }
        else
        {
            //No query string was passed in.
            return null;
        }
    }

    public static string EncryptQueryString(NameValueCollection queryString)
    {
        return EncryptQueryString(queryString, string.Empty);
    }

    public static string EncryptQueryString(NameValueCollection queryString, string myKey)
    {
        //create a string for each value in the query string passed in.
        string tempQueryString = "";
        for (int index = 0; index < queryString.Count; index++)
        {
            tempQueryString += queryString.GetKey(index) + "=" + queryString[index];
            if (index != queryString.Count - 1)
            {
                tempQueryString += QUERY_STRING_DELIMITER;
            }
        }
        return EncryptQueryString(tempQueryString, myKey);
    }

    public static string EncryptQueryString(string queryString)
    {
        return EncryptQueryString(queryString, string.Empty);
    }

    public static string EncryptQueryString(string queryString, string myKey)
    {
        return "?" + HttpUtility.UrlEncode(StringHelpers.Encrypt(queryString, myKey));
    }
}

沒想到URL的QueryString也會影響到download呀~!

Hi, 

亂馬客Blog已移到了 「亂馬客​ : Re:從零開始的軟體開發生活

請大家繼續支持 ^_^