I am working on a WebApplication, and including a Telerik-Report in it. The normal way as described works well.
Now I'm trying to load the report definition from a Database, instead of having a file (request from the boss). So far, I've made it work with a temp-file, code is below. But this is far from nice coding.
My question: can I somehow give a string or stream to the report (instead of a file)?
My current code looks like this:
private readonly string __path = "C:\\my-temp-directory\\Reports\\";
protected void Page_Load(object sender, EventArgs e) {
string contents = /** Get XML from Database **/;
File.WriteAllText(__path + "temp.trdx", contents); // <-- This file I want to omit.
if (!IsPostBack) {
this.reportViewer1.ReportSource.Identifier = "temp.trdx";
this.reportViewer1.ReportSource.IdentifierType = IdentifierType.TypeReportSource;
}
}
Thanks.
Well, the report definition is just an XML so it doesn't really matter where you will obtain it from. Looking at the code I think it won't work, because you have a file, but are using TypeReportSource instead of UriReportSource when setting the IdentifierType.
In this scenario I think you should go with the CustomReportSource. The IdentifierType can be TypeReportSource, UriReportSource and CustomReportSource. The first two won't work in your case, because you don't know the report type and you also do not want to save it to a file. A CustomReportSource will allow you to put your own logic that will fetch the report from the database and send it to the engine. Actually there is a docs article that fits exactly your scenario:
How to Implement a Custom Report Source Resolver
Related
I am trying to make my app stay the way I left it after closing the app. Therefore I want to save set of items from ListView to the settings and I can't figure out how to do that. I've found some solutions but I believe they are outdated as they don't seem to work.
Image shows set of items in ListView which I want to save so they appear there after restarting the app:
Items
This is where I want them to appear:
Settings
And this is part of code that I've tried out so far
private void btn_SaveConfig_Click(object sender, EventArgs e)
{
int i = 0;
Settings.Default["IP"] = tBox_discoverServerFrom.Text;
Settings.Default["DiscoveredServers"] = cBox_discoveredServers.Text;
foreach (var item in lV_groups.Items)
{
var property = new System.Configuration.SettingsProperty("Group"+i);
property.PropertyType = typeof(string);
property.Name = "Group " + i;
Settings.Default.Properties.Add(property);
Settings.Default.Save();
i++;
}
}
I do not think using the Settings API is a great idea if you want to save any significant amount of data.
I would recommend the following
Create a class describing all the data you want to save. To make serialization easier it should have a parameter less constructor and public setters for all properties. This is sometimes called a Data-Transfer-Object (DTO)
Use json to serialize the object to a file. You would normally place the file in a subfolder in the local app data folder: Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData).
Do the reverse when you start the application. If there is a file, use Json to deserialize it and use it however you want.
You may optionally add logic to save the file periodically, this would allow recovery in case of application crashes. You might also want some system to keep more than one file, in case the application or computer crashes in the middle of a save operation, and the file becomes corrupt.
We have a number of SSRS sites serving reports to various locations. Each of these servers all have custom connections in each and every report (don't ask why, that's a tale too torrid to tell). Our goal is to replace all of these custom data sources with a single shared data source for all reports on each server.
To that end, I have created a C# program that will find each report on each server and point the current custom data sources to a currently existing shared data source. This executes and seems to work fine.
My next goal is to use C# to create the shared data source on each server where none currently exists.
My current dilemma arises here:
private static void CreateSharedDataSource(string user, string password, string connection)
{
DataSourceDefinition source = new DataSourceDefinition();
source.CredentialRetrieval = CredentialRetrievalEnum.Store;
source.ConnectString = connection;
source.Enabled = true;
source.EnabledSpecified = true;
source.Extension = "SQL";
source.ImpersonateUser = false;
source.ImpersonateUserSpecified = false;
source.Prompt = "Enter a user name and password to access the data source:";
source.UserName = user;
source.Password = password;
source.WindowsCredentials = true;
source.OriginalConnectStringExpressionBased = true;
source.UseOriginalConnectString = true;
try
{
service.CreateDataSource("DbDataSource", "/DsFolder", false, source, null);
Console.WriteLine("Data source created successfully");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
The data source is created correctly and the user name and password are updated correctly. The problem is that, when I look at the newly created data source on the server, the Connect string property is empty and, yes, the correct value is being passed to it in the method above. If I plug that value into the shared source on the server and test the connection, it works fine, but I cannot get the C# program to update that value itself.
So, is there something subtle I'm missing? Am I misinterpreting a setting up there? Did I set a value wrong?
Clues appreciated.
I've never tried anything like this but a quick bit of research uncovered this which may be helpful.
https://learn.microsoft.com/en-us/dotnet/api/reportservice2010.datasourcedefinition.originalconnectstringexpressionbased?view=sqlserver-2016
It states
"Expression-based connection strings are not supported in shared data
sources."
Assuming the conneciton string is just a plain text string then I would guess that you could set this to false. This may help preserve the string you pass in.
Alright, found my answer. I had a pre-existing data source that was working so, instead of creating it from scratch, I copied that and only changed the name. That created a data source where the Connect string did persist. Comparing the settings in that with what I was setting revealed:
source.UseOriginalConnectString = false;
whereas, my code was:
source.UseOriginalConnectString = true;
Looking that up in docs and it tells me "If true, the value of the ConnectString property is ignored."
Hmmm... that's intuitive. That's not what that sounds like at all. :)
I have a checkbox(Name:tarahi_algouritm) and a button(Name:button1) on my form(Name:frm_choose).I want to save the latest changes on my checkbox as user clicked on the button.it means user run the program and check the checkbox and then click on button and then close the program.when he/she Rerun it,checkbox should be checked.or someway he disable the checkbox and click on button and after another run,checkbox should be disabled.
for this, in application setting(table part) put a checkbox (Name:s_tarahi_algouritm)and choose USER in scope part..as I said changes are apply on checkbox and s_tarahi_algouritm is used for save the latest changes on checkbox.I wrote these codes:
private void frm_choose_Load(object sender, EventArgs e)
{
if (Properties.Settings.Default.s_tarahi_algouritm!=null)
tarahi_algouritm= Properties.Settings.Default.s_tarahi_algouritm;
}
private void button1_Click(object sender, EventArgs e)
{
Properties.Settings.Default.s_tarahi_algouritm = tarahi_algouritm;
Properties.Settings.Default.Save();
}
but When I make changes on checkbox and close the debug and Rerun it,changes are not applied.
what should I do?where is wrong?I am partly beginner so explain explicit.
thank you all
The problem is the settings files are written out in two parts: one to the application settings (which you can't save to) and the other to the user settings (which you can save to). You need to save the user settings (it gets written to your c:\users{userid}... directory).
Look at the most up-voted response to Farzin's link. It explains the issue as well.
Here's a more thorough explanation: App.config: User vs Application Scope
Here's an example.
I created a webform app and added a Settings file to it (called TestSettings.settings). I added two values:
When you run this application it creates a file in the application directory named the same as your executable with .config appended that contains (among other things) a element and a element. But this file only contains the initial values. If you change the value under the element and call Save() it will not update this file. It will create a file:
c:\Users{username}\AppData\Local{appname}{random_dir_name}{version}\user.config
My code to demonstrate this was:
Console.WriteLine(TestSettings.Default["UserValue"]);
TestSettings.Default["UserValue"] = "def";
TestSettings.Default.Save();
I tested many things like:
Properties.Settings.Default.Properties.Add(new System.Configuration.SettingsProperty("a"));
Properties.Settings.Default.Properties["a"].DefaultValue = "b";
Properties.Settings.Default.Save();
it has not error but do not save. In this link:
C# Settings.Default.Save() not saving?
Answered you must add Properties.Settings.Default.Reload(); after saving, I did that but not changed. It seems no one knows the answer.(I read many articles).
It looks like a cancer to me! I suggest you to easily save your settings to a xml file.
Below i add an easy xml saving method:
using System.Xml.Linq;
And
XElement settings;
try
{
settings = XElement.Load("settings.xml"); //beside the app .exe file
}
catch (Exception) // it is first time and you have not file yet.
{
settings = new XElement("settings");
settings.Save("settings.xml");
}
If you want to add new element:
settings.Add(new XElement("firstKey", tarahi_algouritm.Checked.ToString()));
settings.Save("settings.xml");
If you want to read or edit element:
XElement settings = XElement.Load("settings.xml");
string firstKey = settings.Element("firstKey").Value; //reading value
settings.Element("firstKey").Value = "New Value"; //Edit
settings.Save("settings.xml"); //Save
Remember that firstKey is only a name and you can use another names instead.
I want to open a folder from a record pulled up in a form in Epicor. I have created a button and so far it opens up the root folder but I want it to go to a sub-folder with the record's name as the sub folder that will be created from SQL stored procedure when a new record is created.
Here is what I have so far:
private void epiButtonC1_Click(object sender, System.EventArgs args)
{
// ** Place Event Handling Code Here **
string folder = "\\\\MasterServ\\Shared\\Customer Attachments\\";
Process.Start("IExplore.exe", folder);
}
I know something needs to be added at the end of the location to call the folder using the record but im not sure what.
When trying to get data out of a control in Epicor, generally speaking you want to go to the EpiDataView to get the value and not the control itself. There are multiple layers of abstraction going on in the form that make control handling wonky.
From your example for the comments I would do this. Code untested so hopefully I didn't make a typo.
EpiDataView edvUD104 = ((EpiDataView)(oTrans.EpiDataViews["UD104"]));
if (edvUD104.HasRow)
{
string folder = "\\\\MasterServ\\Shared\\Customer Attachments\\"
+ edvUD104.dataView[edvUD104.Row]["Key1"].ToString();
Process.Start("IExplore.exe", folder);
}
Edited for readability.
I see a lot of people coming up with some excessive ways to change the folder location on the fly with flajaxian multiple file upload control.
Was just wondering if the more experienced could take a look at the way I've come up with and let me know if there are any major issues I should be concerned about. (Assuming I have the proper error checking in place.)
I planned on initializing the control as seen below. :
<cc1:FileUploader ID="FileUploader1" runat="server" OnFileReceived="fileUploader_FileReceived" RequestAsPostBack="true">
</cc1:FileUploader>
(I RequestAsPostBack="true" as there are some other controls I need to check in my event handler)
I simply change the HttpFileCollection.SaveAs property in the fileUploader_FileReceived event. Since flajaxian does this one file upload at a time, we can expect that there is only 1 file in the collection (or else we could use a loop).
protected void fileUploader_FileReceived(object sender,
com.flajaxian.FileReceivedEventArgs e)
{
HttpFileCollection files = Request.Files;
// Change path to whichever folder I need
String TempFileName = "C:\\NEW\\PATH\\TO\\Folder\\" + files[0].FileName;
// Save the file.
files[0].SaveAs(TempFileName);
}
This implementation seems to work great as long as the folder is existing! I was just wondering if there is anything technically wrong with an implementation like this, again , assuming all error checking was in place.
Thanks!
A better way to do this would be to use an adapter, and over write the folder location in the
OnFileNameDetermining event. This way, we also get all the goodies with the adapter.
<cc1:FileUploader ID="FileUploader1" runat="server"` OnFileReceived="fileUploader_FileReceived" RequestAsPostBack="true">
<Adapters>
<cc1:FileSaverAdapter runat="server" FolderName="Ups" OnFileNameDetermining="fileUploader_FileDetermined" />
</Adapters>
</cc1:FileUploader>
In the file determined event, we can change the folder location programatically
protected void fileUploader_FileDetermined(object sender, com.flajaxian.FileNameDeterminingEventArgs e)
{
e.FileName = "C:\\NewFolder\\" + e.File.FileName;
}
We can use the FileReceived event to check if the folder exists, and if not, create it.
protected void fileUploader_FileReceived(object sender, com.flajaxian.FileReceivedEventArgs e)
{
int fileIndex = e.Index;
if (fileIndex == 0)
{
// We are on our first file, check if the new folder exists, if not, create it
}
}
What you are doing is fine, although, if you are saving files within the web site, consider using the MapPath method to create a physical folder from a virtual path within the web site
MapPath("/Images/User1")
This my mininal APSX implementation
<fjx:FileUploader ID="FileUploader1" runat="server" OnFileReceived="FileUploader2_FileReceived">
</fjx:FileUploader>
No adapters or folder is specified. When the FileRecevied event fires, I save files to a folder based on the Forms Authentication user name (names do not use characters not allowed in folder names).
Also note that the FileReceivedEventArgs has a reference to the (HTTP) file
e.File
The FileUploader control will show all files processed - you can even set the status code (e.g. 550) if there is an error, which is returned to the client.
Note that, the server call to the FileReceived event does not occur inside a nornal page postback, even if you specify
RequestAsPostBack="true"
So, a PagePreRender does not take place.
The only issue is, how do you perform any other processing at the client after the uploads complete (e.g. showing images uploaded).
Work I have in progress to this end is to use the client side event
FileStateChanged
When the last file is processed
if (file.state > Flajaxian.File_Uploading && isLast) {
I use JQuery to click a hidden submit button. The postback looks through session values stored when the files were saved, and renders back the images into a DIV.
However, an immediate submit causes issues with empty session inside the FileReceived event for some reason (I assume because the internal asynchronous call back has not completed). A pause of a few seconds before initiating the postback works OK.