Вопрос

Создание отчета FastReport несколько источников данных, группировки

Делаю отчет в FastReport по аналогии со статьей в Академии. 
https://academy.terrasoft.ru/documents/technic-sdk/7-16/primer-nastroyki-otcheta

Но мне для отчета нужны несколько источников данных и во многих несколько уровней группировки данных.
Источники данных.

{
    "ProviderName": "MortgageConclusionDataProvider",
    "Schemas": {
        "MortgageConclusionData": {
            "GroupName": {"DataValueType": 1},
            "Account": {"DataValueType": 1},
            "PreparationDate": {"DataValueType": 7},
            "ConclusionType": {"DataValueType": 1}
        },
        "LevelSecurityData": {
            "MortgageConclusion": {"DataValueType": 0},
            "SublimitTypes": {"DataValueType": 0},
            "NameSublimitTypes": {"DataValueType": 1},
            "Groupe": {"DataValueType": 1},
            "TargetUse": {"DataValueType": 1},
            "AmountLimit": {"DataValueType": 5}
        },
        "LocalizableStrings": {
            "ReportTitle": {"DataValueType": 1},
            ...
        }
    }
}

В сервисе прописываю логику:
 

public Task<ReportDataDictionary> GetData(UserConnection userConnection, IReadOnlyDictionary<string, object> parameters) {
            var filter = ExtractFilterFromParameters(userConnection, _entitySchemaUId, parameters);
            var result = new ReportDataDictionary {
                // Заполнить колонки в отчете.
                ["MortgageConclusionData"] = GetMortgageConclusionData(userConnection, _entitySchemaUId, filter),
                ["LevelSecurityData"] = GetLevelSecurityData(userConnection, _entityLevelSecuritySchemaUId),
                ["LocalizableStrings"] = GetLocalizableStrings(userConnection)
            };
            return Task.FromResult(result);
        }

И при формировании отчета ошибка 
 Error while sending request 
    response status: 500 (Internal Server Error)
    request url: ...FastReportService/CreateReport
    method: POST
    request data: {"reportTemplateId":"a1c1f160-a7c2-56a0-edcb-1101dde5a74e","reportCaption":"Заключение","reportSchemaName":"MortgageConclusion","report...

Через Profiler запросы сформировались, данные есть.

Хотелось бы хоть один рабочий пример увидеть, где несколько источников и есть иерархия...
Спасибо!

Нравится

6 комментариев
Лучший ответ

Судя по сообщению из логов, второе исключение происходит в схеме FastReportService, в функции:

[Obsolete("7.15.3")]
[OperationContract]
[WebGet(UriTemplate = "GetReportFile/{key}")]
public Stream GetReportFile(string key) {
	var data = PopFromSessionData(key);
	string contentDisposition = "attachment; filename*=UTF-8''" + data.Key;
	var reportStream = new MemoryStream(data.Value);
	WebResponseProcessor.AssignFileResponseContent(HttpContextAccessor.GetInstance(), "application/pdf; charset=UTF-8", reportStream.Length, contentDisposition);
	return reportStream;
}
 
private KeyValuePair<string, byte[]> PopFromSessionData(string sessionKey) {
	var data = (KeyValuePair<string, byte[]>)UserConnection.SessionData[sessionKey];
	UserConnection.SessionData.Remove(sessionKey);
	return data;
}

То есть падает не внутри Вашего кода отчёта, а при попытке скачать с сервера файл отчёта, вместо него пусто. Отчёт перед этим уже должен был создаться в CreateReport, а в ней происходит первое исключение. Но в этой функции любые ошибки обрабатывает общий блок try:

[Obsolete("7.15.3")]
[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped)]
public string CreateReport(Guid reportTemplateId, string reportCaption, string reportSchemaName, string reportFilters) {
	try {
		var reportParameters = new Dictionary<string, object> {
			["EsqFilters"] = new Dictionary<string, Filters> {
				[reportSchemaName] = JsonConvert.DeserializeObject<Filters>(reportFilters)
			}
		};
		var reportBytes = InternalCreateReport(reportTemplateId, reportParameters);
		return PushToSessionData(new KeyValuePair<string, byte[]>($"{HttpUtility.UrlPathEncode(reportCaption)}.pdf", reportBytes));
	} catch (Exception exception) {
		throw new WebFaultException<FastReportGenerationException>(
			new FastReportGenerationException(exception),
			HttpStatusCode.InternalServerError);
	}
}

Получается, чтобы увидеть, где именно упало при генерации отчёта, нужно для теста убрать этот try, чтобы видеть дальнейший стек вызовов и настоящую ошибку.

 

А у Вас response status: 500 только на конкретном отчёте, который разрабатываете, на остальных нормально?

 

По поводу примеров, кроме описанного в академии, в системе есть ещё стандартные «Знаменательные события контакта» и «Полнота наполнения данными». В первом — несколько источников и схема ContactAnniversariesReportDataProvider, в ней интересующая Вас функция:

public Task<ReportDataDictionary> GetData(UserConnection userConnection,
    IReadOnlyDictionary<string, object> parameters) {
    var contactFilter = ExtractFilterFromParameters(userConnection, _contactEntitySchemaUId, parameters);
    var result = new ReportDataDictionary {
        ["Contact"] = GetContactData(userConnection, _contactEntitySchemaUId, contactFilter),
        ["ContactAnniversary"] = GetContactAnniversaryData(userConnection, _contactAnniversaryEntitySchemaUId,
            contactFilter),
        ["LocalizableStrings"] = GetLocalizableStrings(userConnection)
    };
    return Task.FromResult(result);
}

 Но обратите внимание, выше в коде есть сами функции GetContactData и GetContactAnniversaryData, получающие из базы коллекцию данных с указанным фильтром.

Елена, ошибка 500 происходит на сервере, то есть в логах должна быть более подробная информация, где именно в коде она возникает.

Зверев Александр,

2020-08-05 18:06:11,849 [192] ERROR  Terrasoft.Web.Common.ServiceModel.ErrorHandler ProvideFault - Internal Server Error
System.ServiceModel.Web.WebFaultException`1[Terrasoft.Configuration.Reporting.FastReport.FastReportGenerationException]: Internal Server Error (Дополнительные сведения об ошибке — Terrasoft.Configuration.Reporting.FastReport.FastReportGenerationException: Error during report generation).
2020-08-05 18:06:11,864 [192] ERROR  Terrasoft.WebApp.FileWebEventProvider RaiseInternal - Date: 05.08.2020 18:06:11
Date (UTC): 05.08.2020 15:06:11
 
Exception Message: Internal Server Error
Exception Type: System.ServiceModel.Web.WebFaultException`1[Terrasoft.Configuration.Reporting.FastReport.FastReportGenerationException]
Exception Source: Terrasoft.Configuration
 
Exception Stack Trace:
   в Terrasoft.Configuration.Reporting.FastReport.FastReportService.CreateReport(Guid reportTemplateId, String reportCaption, String reportSchemaName, String reportFilters)
   в SyncInvokeCreateReport(Object , Object[] , Object[] )
   в System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
   в System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
   в System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
   в System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
   в System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
 
SessionID: xxiqbf2pqlqi4uvge2vbjffb
Request URL: /0/rest/FastReportService/CreateReport
Request Path: /0/rest/FastReportService/CreateReport
Request UrlReferrer: http://192.168.222.228:82/0/Nui/ViewModule.aspx
Request Type: POST
User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36
User Host Address: 192.168.10.131
User: Supervisor
Is Authenticated: True
Authentication Type: Forms
Is Secure Connection: False
 
Application Version: 7.16.0.4449
 
Application Virtual Path: /0
Application Trust Level: Full
 
Is Local: False
 
Process ID: 3988
Process Name: w3wp.exe
OS Version: Microsoft Windows NT 10.0.14393.0
Net Framework Version: 4.0.30319.42000
DBExecutor Type: MSSqlExecutor
 
<-->
 
2020-08-05 18:06:11,880 [192] ERROR  Terrasoft.Web.Common.ServiceModel.ErrorHandler HandleError - Internal Server Error
System.ServiceModel.Web.WebFaultException`1[Terrasoft.Configuration.Reporting.FastReport.FastReportGenerationException]: Internal Server Error (Дополнительные сведения об ошибке — Terrasoft.Configuration.Reporting.FastReport.FastReportGenerationException: Error during report generation).
2020-08-05 18:06:11,974 [192] ERROR  Terrasoft.Web.Common.ServiceModel.ErrorHandler ProvideFault - Ссылка на объект не указывает на экземпляр объекта.
System.NullReferenceException: Ссылка на объект не указывает на экземпляр объекта.
   в Terrasoft.Configuration.Reporting.FastReport.FastReportService.PopFromSessionData(String sessionKey)
   в Terrasoft.Configuration.Reporting.FastReport.FastReportService.GetReportFile(String key)
   в SyncInvokeGetReportFile(Object , Object[] , Object[] )
   в System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
   в System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
   в System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
   в System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
   в System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
2020-08-05 18:06:11,974 [192] ERROR  Terrasoft.WebApp.FileWebEventProvider RaiseInternal - Date: 05.08.2020 18:06:11
Date (UTC): 05.08.2020 15:06:11
 
Exception Message: Ссылка на объект не указывает на экземпляр объекта.
Exception Type: System.ServiceModel.FaultException`1[System.NullReferenceException]
Exception Source: 
 
Exception Stack Trace:
 
 
SessionID: xxiqbf2pqlqi4uvge2vbjffb
Request URL: /0/rest/FastReportService/GetReportFile/undefined
Request Path: /0/rest/FastReportService/GetReportFile/undefined
Request Type: GET
User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36
User Host Address: 192.168.10.131
User: Supervisor
Is Authenticated: True
Authentication Type: Forms
Is Secure Connection: False
 
Application Version: 7.16.0.4449
Application Virtual Path: /0
Application Trust Level: Full
Is Local: False
 
Process ID: 3988
Process Name: w3wp.exe
OS Version: Microsoft Windows NT 10.0.14393.0
Net Framework Version: 4.0.30319.42000
DBExecutor Type: MSSqlExecutor
 
<-->
 
2020-08-05 18:06:11,989 [192] ERROR Terrasoft.Web.Common.ServiceModel.ErrorHandler HandleError - Ссылка на объект не указывает на экземпляр объекта.
System.NullReferenceException: Ссылка на объект не указывает на экземпляр объекта.
   в Terrasoft.Configuration.Reporting.FastReport.FastReportService.PopFromSessionData(String sessionKey)
   в Terrasoft.Configuration.Reporting.FastReport.FastReportService.GetReportFile(String key)
   в SyncInvokeGetReportFile(Object , Object[] , Object[] )
   в System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
   в System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
   в System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
   в System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
   в System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)

 

Зверев Александр,

Куда смотреть, что проверять?)

 

Судя по сообщению из логов, второе исключение происходит в схеме FastReportService, в функции:

[Obsolete("7.15.3")]
[OperationContract]
[WebGet(UriTemplate = "GetReportFile/{key}")]
public Stream GetReportFile(string key) {
	var data = PopFromSessionData(key);
	string contentDisposition = "attachment; filename*=UTF-8''" + data.Key;
	var reportStream = new MemoryStream(data.Value);
	WebResponseProcessor.AssignFileResponseContent(HttpContextAccessor.GetInstance(), "application/pdf; charset=UTF-8", reportStream.Length, contentDisposition);
	return reportStream;
}
 
private KeyValuePair<string, byte[]> PopFromSessionData(string sessionKey) {
	var data = (KeyValuePair<string, byte[]>)UserConnection.SessionData[sessionKey];
	UserConnection.SessionData.Remove(sessionKey);
	return data;
}

То есть падает не внутри Вашего кода отчёта, а при попытке скачать с сервера файл отчёта, вместо него пусто. Отчёт перед этим уже должен был создаться в CreateReport, а в ней происходит первое исключение. Но в этой функции любые ошибки обрабатывает общий блок try:

[Obsolete("7.15.3")]
[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped)]
public string CreateReport(Guid reportTemplateId, string reportCaption, string reportSchemaName, string reportFilters) {
	try {
		var reportParameters = new Dictionary<string, object> {
			["EsqFilters"] = new Dictionary<string, Filters> {
				[reportSchemaName] = JsonConvert.DeserializeObject<Filters>(reportFilters)
			}
		};
		var reportBytes = InternalCreateReport(reportTemplateId, reportParameters);
		return PushToSessionData(new KeyValuePair<string, byte[]>($"{HttpUtility.UrlPathEncode(reportCaption)}.pdf", reportBytes));
	} catch (Exception exception) {
		throw new WebFaultException<FastReportGenerationException>(
			new FastReportGenerationException(exception),
			HttpStatusCode.InternalServerError);
	}
}

Получается, чтобы увидеть, где именно упало при генерации отчёта, нужно для теста убрать этот try, чтобы видеть дальнейший стек вызовов и настоящую ошибку.

 

А у Вас response status: 500 только на конкретном отчёте, который разрабатываете, на остальных нормально?

 

По поводу примеров, кроме описанного в академии, в системе есть ещё стандартные «Знаменательные события контакта» и «Полнота наполнения данными». В первом — несколько источников и схема ContactAnniversariesReportDataProvider, в ней интересующая Вас функция:

public Task<ReportDataDictionary> GetData(UserConnection userConnection,
    IReadOnlyDictionary<string, object> parameters) {
    var contactFilter = ExtractFilterFromParameters(userConnection, _contactEntitySchemaUId, parameters);
    var result = new ReportDataDictionary {
        ["Contact"] = GetContactData(userConnection, _contactEntitySchemaUId, contactFilter),
        ["ContactAnniversary"] = GetContactAnniversaryData(userConnection, _contactAnniversaryEntitySchemaUId,
            contactFilter),
        ["LocalizableStrings"] = GetLocalizableStrings(userConnection)
    };
    return Task.FromResult(result);
}

 Но обратите внимание, выше в коде есть сами функции GetContactData и GetContactAnniversaryData, получающие из базы коллекцию данных с указанным фильтром.

Зверев Александр,

Спасибо за помощь, 

«Знаменательные события контакта» нашла, сделала полностью по аналогии. Та же ошибка.
Ошибка исчезает, как только убираю второй источник данных(
Может быть дело в версии, отчет на 16.1 - наша 16.0...

Если дело в версии, зарегистрируйте тестовый сайт и проверьте такое же там.

Показать все комментарии