Tuesday, June 3, 2008

Use stored credential for report created by c# code

In my current project i have created an interface through which admin can generate the report he wants from any of the table (or combination of tables) from any DB in the server. The interface is generating the xml Report Defination (rdl) and publishing it with the reporting service web service.
Now the problem came with the datasource of the report. When i publish the report it was showing the username and password input box in the report viewer. If i put those it was running beautifulluy. But it was not what i wanted. None of us will bother to give the UID and password everytime. Here is the sample of code i used to generate the report

static int zIndex = 1;
string serverName = "localhost";
string reportVirtualPath = "LocalReportServer";
string parentFolder = "QuoteReports";
string dataSetName = "DSSOP";
string dataSourceName = "DynamicDataSource";
string parTabName = "bodyTable";

void deployReport(string reportName, string reportDefination)// reportDefination is the xml rdl
{
ReportingService2005 rs = new ReportingService2005();
rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
byte[] byteRDL;
System.Text.UTF8Encoding encoder = new UTF8Encoding();
byteRDL = encoder.GetBytes(reportDefination);
Property[] rsProperty = new Property[10];
//Property property = new Property();
Warning[] warnings;
try
{
warnings = rs.CreateReport(reportName, "/" + parentFolder, true, byteRDL, null);
}
catch (System.Web.Services.Protocols.SoapException ex)
{
tdMessage.InnerHtml = "Exception in publiching report.
" + ex.Message + "
";
return;
}
}

I was using report-specific datasource with authentication. My sample datasource section of the RDL is below
<datasource name="Personal">
<?xml:namespace prefix = rd /><rd:datasourceid>1a234378-11f1-4dc0-bc74-91df6d7d94f7</rd:datasourceid>
<connectionproperties>
<dataprovider>SQL</dataprovider>
<connectstring>Data Source=SODC42\SQLEXPRESS;Initial Catalog=SOP;UID=sa;password=123456;</connectstring>
</connectionproperties>
</datasource>

Though i was putting the connection string with UID and password, still it was showing the textboxes for username and password.
After a lot of google i found that reporting service uses two connection strings 1) one for connection to the report server 2) another for connection the report server to the databse (In mycase the both of report server and DB server is same express version in localhost). The connection string supplied in the RDL is for the first purpose and the second connection information is stored with the DataSource information in the ReportServer DB.
Then i open the report with the reportmanager (http://localhost/reports) and edit the report. In the editor i found the datasources link where i saw the "Credentials supplied by the user running the report" radio is selected. I canged the selection to "Credentials stored securely in the report server" and gave the desired credentials. Then i saw the report is not showinf the text boxes.
Now it was clear that the problem is with the DataSource not with the RDL. Then i went with the idea of using SharedDataSource and attach it with the report. While deploying the report i was checking if the shared datasource is already existing. If not then create it. Here is the code for creating the shared datasource.

DataSourceDefinition def = new DataSourceDefinition();
def.CredentialRetrieval = CredentialRetrievalEnum.Store;
def.ConnectString = ReportConnection.GetConnection("SOP").ConnectionString;
def.Enabled = true;
def.EnabledSpecified = true;
def.Extension = "SQL";
def.ImpersonateUser = false;
def.ImpersonateUserSpecified = true;
def.WindowsCredentials = false;
def.UserName = "sa";
def.Password = "123456";
rs.CreateDataSource(dataSourceName, dataSourcePath, true, def, null);
rs.SetDataSourceContents(dataSourcePath + "/" + dataSourceName, def);

Note:Before creating you have to check whether it already exists of not. And also the folder structure.
The rdl for datasource :
<DataSources>
<DataSource Name="DynamicDataSource">
<DataSourceReference>/Data Sources/DynamicDataSource</DataSourceReference>
</DataSource>
</DataSources>
Now the report is running fine.
But still there was something hitting in my mind. Why i shall use SharedDataSource? I shall use report specific datasource. But how?
After some days lots of RnD s i found it. It is totally my assumtion. I have no idea how far it is true. But it works.
The report specific datasources you have to keep in a folder "Data Sources" in the same directory as the report and then only the report can use it. So i created the datasource in the report folder's "Data Sources" folder. And so far it is running.

Download Sample Project
For information about the project refer to my other post
Generate Your Dynamic Report Through Reporting Service

2 comments:

Suman said...

Hey i have seen your post on reportring services for "Use stored credential for report created by c# code". I am really working the same way like generating the RDL file by giving an interface for the reports to select table and columns and generate the RDL, datasource and then publish report on report server and then view it from the report server on a report viewer. Here i am actually facing a problem.

When i select some columns then the rdl is generating (its generating if i select all fields also) but there is an exception if many or all fields are selected and i get an exception given belwo:

System.Web.Services.Protocols.SoapException: The Description field has a value that is not valid. ---> Microsoft.ReportingServices.Diagnostics.Utilities.InvalidElementException: The Description field has a value that is not valid.
at Microsoft.ReportingServices.Library.ItemProperties..ctor(Property[] properties, ItemType itemType)
at Microsoft.ReportingServices.Library.CatalogItemCreator.CreateItem()
at Microsoft.ReportingServices.Library.CreateReportAction._CreateReport(String report, String parent, Boolean overwrite, Byte[] definition, Property[] properties)
at Microsoft.ReportingServices.Library.CreateReportAction.CreateReport(Guid batchId, String report, String parent, Boolean overwrite, Byte[] definition, Property[] properties)
at Microsoft.ReportingServices.WebServer.ReportingService.CreateReport(String Report, String Parent, Boolean Overwrite, Byte[] Definition, Property[] Properties, Warning[]& Warnings)
--- End of inner exception stack trace ---
at Microsoft.ReportingServices.WebServer.ReportingService.CreateReport(String Report, String Parent, Boolean Overwrite, Byte[] Definition, Property[] Properties, Warning[]& Warnings)

AND THE CODE WHERE IAM FACING PROBLEM IS GIVEN BELOW:

// Set the description of the report to list the server name, table
// and fields used
Property newProp = new Property();
newProp.Name = "Description";
newProp.Value = myPropertyValue;
Property[] props = new Property[1];
props[0] = newProp;

// Create the report
// Properties can be passed as Nothing
warnings = RS.CreateReport(reportName, parentPath, true, definition, props);


Can you please suggest me a solution. And can you please send me the UI design for this and also for the parametre sending reports. I will be greatly thanks ful to you if you can do this TARUN GOSH.

Please Mail me at rayabharapusuman@gmail.com
r_suman918@yahoo.com


Thanks In Advance.
Nice TO see your BLOG

Suman said...

Hey i have seen your post on reportring services for "Use stored credential for report created by c# code". I am really working the same way like generating the RDL file by giving an interface for the reports to select table and columns and generate the RDL, datasource and then publish report on report server and then view it from the report server on a report viewer. Here i am actually facing a problem.

When i select some columns then the rdl is generating (its generating if i select all fields also) but there is an exception if many or all fields are selected and i get an exception given belwo:

System.Web.Services.Protocols.SoapException: The Description field has a value that is not valid. ---> Microsoft.ReportingServices.Diagnostics.Utilities.InvalidElementException: The Description field has a value that is not valid.
at Microsoft.ReportingServices.Library.ItemProperties..ctor(Property[] properties, ItemType itemType)
at Microsoft.ReportingServices.Library.CatalogItemCreator.CreateItem()
at Microsoft.ReportingServices.Library.CreateReportAction._CreateReport(String report, String parent, Boolean overwrite, Byte[] definition, Property[] properties)
at Microsoft.ReportingServices.Library.CreateReportAction.CreateReport(Guid batchId, String report, String parent, Boolean overwrite, Byte[] definition, Property[] properties)
at Microsoft.ReportingServices.WebServer.ReportingService.CreateReport(String Report, String Parent, Boolean Overwrite, Byte[] Definition, Property[] Properties, Warning[]& Warnings)
--- End of inner exception stack trace ---
at Microsoft.ReportingServices.WebServer.ReportingService.CreateReport(String Report, String Parent, Boolean Overwrite, Byte[] Definition, Property[] Properties, Warning[]& Warnings)

AND THE CODE WHERE IAM FACING PROBLEM IS GIVEN BELOW:

// Set the description of the report to list the server name, table
// and fields used
Property newProp = new Property();
newProp.Name = "Description";
newProp.Value = myPropertyValue;
Property[] props = new Property[1];
props[0] = newProp;

// Create the report
// Properties can be passed as Nothing
warnings = RS.CreateReport(reportName, parentPath, true, definition, props);


Can you please suggest me a solution. And can you please send me the UI design for this and also for the parametre sending reports. I will be greatly thanks ful to you if you can do this TARUN GOSH.

Please Mail me at rayabharapusuman@gmail.com
r_suman918@yahoo.com


Thanks In Advance.
Nice TO see your BLOG