Passing parameters to remote SSRS report from ASP.NET MVC application - asp.net

I have an ASP.NET MVC application that uses SSRS for reporting (using a web form and report viewer). I would like to pass two parameters dynamically to the remote report. My current implementation stores the parameters in session, which works fine on VS Development Server, but the variable is null on IIS, upon retrieval in the web form.
Here is the controller method that calls the view
public ActionResult ShowReport(string id)
{
var reportParameters = new Dictionary<string, string>();
reportParameters.Add("Param1", id);
reportParameters.Add("Param2", "user1");
Session["reportParameters"] = reportParameters;
return View("ReportName");
}
And here is how I attempt to retrieve the parameters from the web form
protected void Page_Load(object sender, EventArgs e)
{
var reportParameters = (Dictionary<string, string>)Session["reportParameters"];
foreach (var item in reportParameters)
{
ReportParameter rp = new ReportParameter(item.Key, item.Value);
ReportViewer1.ServerReport.SetParameters(rp);
}
}
Anyone know why Session["reportParameters"] is null?
Or is there some other way of passing these parameters?

You can do it too:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
try
{
var js = new JavaScriptSerializer();
string reportPath= Request.QueryString["LocalReport"];
string parametersTemp = Request.QueryString["ParametersReport"];
List<ReportParameter> parameters = null;
if (parametrosTemp != "")
{
parameters = JsonConvert.DeserializeObject
<List<ReportParameter>>(parametrosTemp);
}
GenerateReport(reportPath, parameters );
}
catch (Exception ex) {
statusReport.Value = ex.Message;
}
}
}
private void GenerateReport(string reportPath, List<ReportParameter> reportParameters)
{
reportCurrent.ProcessingMode = ProcessingMode.Remote;
ServerReport serverReport = reportCurrent.ServerReport;
serverReport.ReportServerUrl =
new Uri(AppSettings.URLReportServer);
serverReport.ReportPath = reportPath;
serverReport.Refresh();
if (reportParameters != null)
{
reportCurrent.ServerReport.SetParameters(reportParameters);
}
}

Is the problem that Session["reportParameters"] is null or is it that you don't get any parameters added to your report? Because your code, as it stands, won't add parameters to your report even if you pass them across properly and so the report parameters will be null.
SetParameters takes IEnumerable<ReportParameter> (usually a List), not a ReportParameterobject. Your code should look more like this:
protected void Page_Load(object sender, EventArgs e)
{
var reportParameters = (Dictionary<string, string>)Session["reportParameters"];
List<ReportParameter> parameters = new List<ReportParameter>();
foreach (var item in reportParameters)
{
parameters.Add(new ReportParameter(item.Key, item.Value););
}
ReportViewer1.ServerReport.SetParameters(parameters);
}

Related

Logging Request and response to Application Insight

I'm trying to log API request payload and response data to Azure Application Insight. Using trace I can able to log. but I want to know what is the best way to log request and response data to application insight. Because data is huge, no.of API calls will be more. I can't just trace hundreds of thousands of request and response data using tracing. I tried some of the blogs like using ITelemetryInitializer/ httpcontext.feature,get, but no luck.
I want to log from c# .Net framework, Web API, not .NET Core.
Sample code which I tried.
public class AzureRequestResponseInitializer : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
var requestTelemetry = telemetry as RequestTelemetry;
if (requestTelemetry != null && (HttpContext.Current.Request.HttpMethod == HttpMethod.Post.ToString() || HttpContext.Current.Request.HttpMethod == HttpMethod.Get.ToString()))
{
using (var reader = new StreamReader(HttpContext.Current.Request.InputStream))
{
string requestBody = reader.ReadToEnd();
requestTelemetry.Properties.Add("body", requestBody);
}
}
You can achieve it by implementing IHttpModule that using Application Insight's TelemtryClient, see the following code:
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.DataContracts;
using Contoso.Services.Logging.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
namespace Contoso.Services.Logging.Modules
{
public class CaptureTrafficModule : IHttpModule
{
public TelemetryClient Telemetry { get; set; }
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
context.EndRequest += new EventHandler(context_EndRequest);
Telemetry = new TelemetryClient();
}
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
HttpResponse response = HttpContext.Current.Response;
OutputFilterStream filter = new OutputFilterStream(response.Filter);
response.Filter = filter;
app.Context.Items["Filter"] = filter;
StringBuilder request = new StringBuilder();
// Write All The Headers too :
//foreach (string key in app.Request.Headers.Keys)
//{
// request.Append(key);
// request.Append(": ");
// request.Append(app.Request.Headers[key]);
// request.Append("\n");
//}
//request.Append("\n");
byte[] bytes = app.Request.BinaryRead(app.Request.ContentLength);
if (bytes.Count() > 0)
request.Append(Encoding.ASCII.GetString(bytes));
app.Request.InputStream.Position = 0;
string operationName = $"{app.Request.HttpMethod} {app.Request.FilePath}";
string activityId = System.Diagnostics.Activity.Current.RootId;
app.Context.Items["OperationName"] = operationName;
app.Context.Items["ActivityId"] = activityId;
using (var logRequest = Telemetry.StartOperation<RequestTelemetry>(operationName, System.Diagnostics.Activity.Current.RootId, System.Diagnostics.Activity.Current.RootId))
{
try
{
//logRequest.Telemetry.Id = $"10-{activityId}";
logRequest.Telemetry.Url = app.Request.Url;
logRequest.Telemetry.Properties["RequestBody"] = request.ToString();
}
catch (Exception ex)
{
logRequest.Telemetry.Success = false;
Telemetry.TrackException(ex);
//throw;
}
}
}
void context_EndRequest(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
OutputFilterStream filter = null;
string operationName = "", activityId = Guid.Empty.ToString(), responseStr = "NONE";
if (app.Context.Items.Contains("OperationName"))
operationName = app.Context.Items["OperationName"].ToString();
if (app.Context.Items.Contains("ActivityId"))
activityId = app.Context.Items["ActivityId"].ToString();
if (app.Context.Items.Contains("Filter"))
{
filter = (OutputFilterStream)app.Context.Items["Filter"];
responseStr = filter.ReadStream();
}
using (var logResponse = Telemetry.StartOperation<RequestTelemetry>(operationName, activityId, activityId))
{
try
{
//logResponse.Telemetry.Id = $"20-{activityId}";
logResponse.Telemetry.Url = app.Request.Url;
logResponse.Telemetry.Properties["ResponseBody"] = responseStr.ToString();
}
catch (Exception ex)
{
logResponse.Telemetry.Success = false;
Telemetry.TrackException(ex);
//throw;
}
}
}
public void Dispose()
{
//Does nothing
}
}
}
This question is answered in https://thirum.wordpress.com/2019/08/19/logging-the-http-response-body-in-application-insights/
Please take a look.

Pass values to a button from function

I have a function which is receiving parameters from another function and I have to pass these parameters to a button when it's execution get's complete !
async void CallCompanyApi(String CompanyGp, string CompanyId)
{
First.IsVisible = false;
Second.IsVisible = true;
// Next_Clicked(CompanyGp,CompanyId)
}
private void Next_Clicked(object sender, EventArgs e)
{
}
I have to pass these 2 parameters to that button !
you need to create class level variables to store these values
string _CompanyGp;
string _CompanyId;
async void CallCompanyApi(String CompanyGp, string CompanyId)
{
First.IsVisible = false;
Second.IsVisible = true;
// store the parameters in the class level variables
_CompanyGp = CompanyGp;
_CompanyId = CompanyId;
}
private void Next_Clicked(object sender, EventArgs e)
{
// you can now just reference _CompanyGp and _CompanyId
}
FYI, this is basic C# and really has nothing specific to do with Xamarin
Welcome to SO!
If CallCompanyApi and Next_Clicked located in different class, you can store them in Xamarin Forms by using Preferences.
using Xamarin.Essentials;
async void CallCompanyApi(String CompanyGp, string CompanyId)
{
First.IsVisible = false;
Second.IsVisible = true;
//Next_Clicked(CompanyGp,CompanyId)
Preferences.Set("CompanyGp", CompanyGp);
Preferences.Set("CompanyId", CompanyId);
}
Then in another class, click button will get them:
private void Next_Clicked(object sender, EventArgs e)
{
var CompanyGp = Preferences.Get("CompanyGp", "default_value");
var CompanyId = Preferences.Get("CompanyId", "default_value");
}
Else if they are in the same class, you can use the way as Jason's said.
============================Update=========================
You can set a default value if needed, such as follow:
var CompanyGp = Preferences.Get("CompanyGp", "Company_A");
var CompanyId = Preferences.Get("CompanyId", "1");
Defalut CompanyGp is Company_A, and default CompanyId is 1.

How to get Devexpress XtraGrid control selected row

I've a devexpress XtraGrid Control. But, I couldn't get the ID of a by default selected row when the winform loads. I know how to get it when the user clicks on the grid.
Here is the code snapshot:
private void Form1_Load(object sender, EventArgs e)
{
grid1.DataSource = bindData(DataClassesDataContext.Table1.ToList());
ID = Convert.ToInt32(gridView.GetRowCellValue(gridView.FocusedRowHandle, "ID"));
XtraMessageBox.Show(ID.ToString());
}
public BindingSource bindData(object obj)
{
BindingSource ctBinding;
try
{
ctBinding = new BindingSource();
ctBinding.DataSource = obj;
return ctBinding;
}
catch (Exception ex)
{
XtraMessageBox.Show(ex.Message, "Database Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;
}
}
If I understand you correctly, you need something like this:
private void Form1_Shown(object sender, EventArgs e)
{
grid1.DataSource = bindData(DataClassesDataContext.Table1.ToList());
var item = gridView.GetFocusedRow() as YourDataType
if(item != null)
{
ID = item.ID;
XtraMessageBox.Show(ID.ToString());
}
}
assuming what your bindData returns a typed collection of some kind.
** Update **
Moving the code to form_Shown seemed to do the trick.

user control properties

i have a detail view with below markup and data source of this detail view is from stored procedure "spDocResult" like below:
select DocId,TransId,FileId,Filename,ContentType,Data,DocumentNo,Title,TRANSMITTAL
from DocumentSum2
where (DocId=#Docid)AND(Transid=#Transid)
one field of this detail view should be show Efile Names so i have made 1 user control for that
public partial class FileTemp : System.Web.UI.UserControl
{
private EDMSDataContext _DataContext;
private IEnumerable<tblFile> _Efiles;
public IEnumerable<tblFile> Efiles
{
set { _Efiles = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
}
protected void LinkButton1_Command(object sender, CommandEventArgs e)
{
if (e.CommandName == "Download")
{
_DataContext = new EDMSDataContext();
//you can get your command argument values as follows
string FileId = e.CommandArgument.ToString();
int _FileId = Convert.ToInt32(FileId);
tblFile Efile = (from ef in _DataContext.tblFiles
where ef.FileId == _FileId
select ef).Single();
if (Efile != null)
{
download(Efile);
}}}
private void download ( tblFile Efile)
{
Byte[] bytes = (Byte[])Efile.Data.ToArray();
Response.Clear();
Response.Buffer = true;
Response.Charset = "";
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.ContentType = Efile.ContentType.ToString();
Response.AddHeader("content-disposition", "attachment;filename="
+ Efile.FileName.ToString());
Response.BinaryWrite(bytes);
Response.Flush();
Response.End();
}
public override void DataBind()
{
base.DataBind();
GridViewEfile.DataSource = _Efiles;
GridViewEfile.DataBind();
}
}
now i have problem because datasource of detailview comes from a stored procedure and properties of user control is from tblFile, so when i use DetailsView1_DataBound i do not know how i have to get user control properties.when i use below code, i have error
can not implicity convert type string to system.collection.generic.iEnumerable<tblfile>
i have error for this line
fileList.Efiles = docresult.Filename;
protected void DetailsView1_DataBound(object sender, EventArgs e)
{
spDocResultResult docresult = (spDocResultResult)DetailsView1.DataItem;
FileTemp fileList = (FileTemp)DetailsView1.FindControl("FileTemp1");
fileList.Efiles = docresult.Filename;
fileList.DataBind();
}
This might not be a data binding issue at all. It's a little hard to gather from the context, but...
FileTemp fileList = (FileTemp)DetailsView1.FindControl("FileTemp1");
fileList.Efiles = docresult.Filename;
Is fileList.Efiles a list of items that you just want to assign a file name to? If so, you might just need to foreach through them.
foreach (var file in fileList.Efiles)
{
file.FileName = docresult.Filename;
}
Also, add this line to your Efiles declaration to solve the Get accessor error.
public IEnumerable<tblFile> Efiles
{
get { return _Efiles; } // <- here
set { _Efiles = value; }
}

Posting data between Asp.Net Web Pages

I have a list of strings, which are generated on a imagebutton_click method. I want to be able to use this list in another webpage.
How ever im not quite sure how to go about posting it between the two pages.
I have the following code below:
protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
{
RadGrid rg = RadGrid1;
//Get selected rows
GridItemCollection gdc = (GridItemCollection)rg.SelectedItems;
foreach (GridItem gi in gdc)
{
if (gi is GridDataItem)
{
GridDataItem gdi = (GridDataItem)gi;
if (!string.IsNullOrEmpty(gdi["Email"].Text))
{
string client = gdi["Email"].Text;
//Creating a List of Clients to be Emailed
emailList.Add(email);
}
}
//Enable the Prepare Email Page
PageView2.Selected = true;
}
protected void ImageButton2_Click(object sender, ImageClickEventArgs e)
{
if (emailList.Count != 0)
{
for (int i = 0; i < emailList.Count; i++)
{
_to = emailList[i].ToString() + ";";
}
}
else
{
_to = emailList[1].ToString();
}
//Processing Client Email
string _from = sec.GetCurrentUserEmail("test");
string _cc = "";
string _subject = SubjectTB.Text;
string _body = EmailEditor.Content;
string _tempTo = sec.GetCurrentUserEmail("temp");
string _msg = sec.SendMail(_tempTo, _cc, _from, _subject, _body, "");
if (_msg == "success")
{
//Thank the user and record mail was delivered sucessfully
TestPanel.Visible = true;
}
}
How do I get the values of emailList to be passed through to ImageButton2_click(object sender, ImageClickEventArgs e). Currently it just passes through a null value. I gather I need to use HTML forms to do the request. Thanks.
I'm guessing that emailList is a private variable? Wouldn't you be able to add that to the LoadControlState and SaveControlState so that it'll be available for ImageButton2_Click later?
Here is an example: http://msdn.microsoft.com/en-us/library/system.web.ui.control.loadcontrolstate%28v=vs.80%29.aspx
Another possibility is hidden field, that might be the simplist way, but not as secure.
You can get a good idea about state management in ASP.Net here. For your case if button1 and button2 are in the same aspx page, Viewstate would be a good idea. If they are in diferent pages then use Session state management.

Resources