Как войти в базу данных SQL для подключения к отчету crystal с помощью ASP.NET контроллер MVC 5 (C#)
Привет,
У меня есть решение Visual Studio 2017 с несколькими проектами. Один из проектов содержит все мои отчеты. Веб-приложение было создано с использованием языка C#, ASP.NET MVC 5, MS SQL 2014, и я использую Entity Framework Code-first для своих моделей данных.
Конкретный отчет, который я создал, довольно сложен. Таким образом, он собирает финансовые данные из нескольких таблиц данных, а затем отображает "отчет-подобный" отчет для конкретного клиента. Чтобы позволить пользователю сохранять отчеты, я создал следующие модели данных отчетов для хранения полученных данных из остальной части приложения:
Я использую надстройку Crystal Reports для Visual Studio.
1) ежемесячные платежи клиентов - соединяет отчет "MonthlyCustomerPayments.rpt" с моделью данных "CustomerMonthlyPaymentsReport". Это "основной" или "основной" отчет.
Следующие подотчеты/модели связаны через первичный ключ "ReportId" с основным отчетом/моделью.
2) резюме клиента - "CustomerSummary.rpt" - модель данных "CustomerSummary".
3) сводка платы за обслуживание клиентов - "CustomerServiceFeeSummary.rpt" модель данных "CustomerServiceFeeSummary".
4) сводка профиля учетной записи клиента - "CustomerAccountProfileSummary.rpt" - модель данных "CustomerAccountProfileSummary".
5) сводка по счету клиента - "CustomerAccountSummary.rpt" - модель данных "CustomerAccountSummary".
6) сводка обслуживания клиентов - "CustomerServiceSummary.rpt" - модель данных "CustomerServiceSummary".
7) Сведения о Службе поддержки транзакций - "обслуживание клиентов подробности операции" - "CustomerServiceTransactionDetails" модели данных.
Я надеюсь, что все вышесказанное имеет смысл с точки зрения настройки моделей данных и соответствующих им отчетов.
У меня есть контроллер, который собирает данные для каждой таблицы данных, сохраняет их, а затем отображает таблицы отчетов в виде Razor. На этом представлении у меня есть две кнопки: одна для "экспорта в PDF", а другая для "экспорта в Excel".
Таким образом, идея заключается в том, что клиент генерирует отчет для указанного диапазона дат, сохраняет его, а затем имеет возможность экспортировать отчет в PDF или Excel foemat.
Я буду использовать экспорт PDF в качестве примера. У меня есть следующий код для кнопки экспорта PDF в CustomerMonthlyPaymentReportsController:
public ActionResult ExportReportPDF(int id) { string ServerName = System.Configuration.ConfigurationManager.AppSettings["DbServer"].ToString(); //Database server name to which report connected string DataBaseName = System.Configuration.ConfigurationManager.AppSettings["DbName"].ToString(); //Database name to which report connected string UserID = System.Configuration.ConfigurationManager.AppSettings["DbUser"].ToString(); //Database user name to which report connected string Password = System.Configuration.ConfigurationManager.AppSettings["DbPwd"].ToString(); //Database user password to which report connected ReportDocument crReportDocument = new ReportDocument(); crReportDocument.Load(Path.Combine(Server.MapPath("~/Reports/Admin"), "MonthlyCustomerPayments.rpt")); crReportDocument.SetDataSource(db.CustomerMonthlyPaymentsReport.Where(x => x.ReportId == id).ToList()); //crReportDocument.SetDatabaseLogon(UserID, Password); Logon(crReportDocument, ServerName, DataBaseName, UserID, Password); //crReportDocument = prepareReport(crReportDocument); Response.Buffer = false; Response.ClearContent(); Response.ClearHeaders(); string reportDescription = db.CustomerMonthlyPaymentsReport.Where(x => x.ReportId == id).Select(x => x.ReportDescription).First(); try { Stream stream = crReportDocument.ExportToStream(ExportFormatType.PortableDocFormat); stream.Seek(0, SeekOrigin.Begin); string savedFileName = string.Format(reportDescription + ".pdf"); return File(stream, "application/pdf", savedFileName); } catch { throw; } }
Следующий код используется для входа в каждый отчет с использованием учетных данных SQL server, хранящихся в файле Web.Config:
//Check whether crytal report can login to the server private bool Logon(ReportDocument cr, string server, string database, string user_id, string password) { // Declare and instantiate a new connection info object. ConnectionInfo ci; ci = new ConnectionInfo(); ci.ServerName = server; ci.DatabaseName = database; ci.UserID = user_id; ci.Password = password; //password; // ci.IntegratedSecurity = false; // If the ApplyLogon function fails then return a false for this function. // We are applying logon information to the main report at this stage. if (!ApplyLogon(cr, ci)) { return false; } // Declare a subreport object. SubreportObject subobj; // Loop through all the report objects and locate subreports. // If a subreport is found then apply logon information to // the subreport. foreach (ReportObject obj in cr.ReportDefinition.ReportObjects) { if (obj.Kind == ReportObjectKind.SubreportObject) { subobj = (SubreportObject)obj; if (!ApplyLogon(cr.OpenSubreport(subobj.SubreportName), ci)) { return false; } } } // Return True if the code runs to this stage. return true; }
Следующий код вызывается методом входа в систему:
private bool ApplyLogon(ReportDocument cr, ConnectionInfo ci) { // This function is called by the "Logon" function // It loops through the report tables and applies // the connection information to each table. // Declare the TableLogOnInfo object and a table object for use later. TableLogOnInfo li; // For each table apply connection info. foreach (CrystalDecisions.CrystalReports.Engine.Table tbl in cr.Database.Tables) { li = tbl.LogOnInfo; li.ConnectionInfo.ServerName = ci.ServerName; li.ConnectionInfo.DatabaseName = ci.DatabaseName; li.ConnectionInfo.UserID = ci.UserID; li.ConnectionInfo.Password = ci.Password; tbl.ApplyLogOnInfo(li); tbl.Location = ci.DatabaseName + ".dbo." + tbl.Name; // Verify that the logon was successful. // If TestConnectivity returns false, correct table locations. if (!tbl.TestConnectivity()) { return false; } } return true; }
Я надеюсь, что приведенный выше код имеет смысл. То, что я пытаюсь сделать, - это заставить приложение войти в базу данных, используя конкретные учетные данные, которые я указываю в конфигурации.Веб-файл. Это делается для того, чтобы я мог тестировать отчеты на своем компьютере разработчика и указывать учетные данные для входа на рабочий (живой) сервер.
Проблема, с которой я сталкиваюсь, заключается в том, что все это прекрасно работает на моем компьютере Dev, но дает мне следующую ошибку на производственном сервере:
"Ошибка в файле MonthlyCustomerPayments 5412_8572_{99689A9A-3AB1-47CF-B744-2DA06097BBDD}.rpt:
Не удается подключиться: неверные параметры входа в систему."
Из того, что я смог выяснить, кажется, что он берет имя SQL server моего Dev PC, встроенное в отчет, и мой код выше для входа в экземпляр SQL server производственного сервера игнорируется.
Я знаю, что это логическое объяснение моей конкретной проблемы, но я опубликовал на многих форумах об этом, и люди, похоже, неправильно понимают детали и сложность настройки моего отчета.
Я надеюсь, что кто-то, кто использовал Entity Framework и Crystal Reports в приложении MVC с отчетом и несколькими вложенными отчетами, может дать мне совет по этому вопросу.
Спасибо, что прочитали это, и я с нетерпением жду любых предложений/советов.
Что я уже пробовал:
Я пробовал бесчисленные предложения по использованию ASPX и CrstalReport Viewer, но боюсь, что они не очень хорошо работают с этим сложным отчетом, который имеет несколько вложенных отчетов.
Приведенный выше код я реализовал по предложению человека на другом форуме, чтобы регистрировать каждый отчет/подотчет в базе данных.