Using Rotativa 1.6.4 from NuGet and have noticed the following issue using the code below.
ActionAsPdf hangs randomly for indeterminate amount of time.
Code below that is hanging:
var pdfResult = new ActionAsPdf("Report", new {id = Request.Params["id"]})
{
Cookies = cookieCollection,
FormsAuthenticationCookieName = FormsAuthentication.FormsCookieName,
CustomSwitches = "--load-error-handling ignore"
};
Background info that may help:
The customSwitches is in use to ignore a documented issue calling wkhtmltopdf.exe using the ActionAsPdf, but it does not suppress errors in the code only in the wkhtmltopdf call.
Observations, usage and testing:
It works but when running the application (whether or not stepping through code), it can be anywhere from 10 seconds up to about 4 minutes between hitting the pdfResult = new ActionAsPdf and finally entering into the "Report" action being called. Can't discern anything actually happening in the output window of Visual Studio, no errors are being thrown that I have found. Just random slow transition into the Reports() action.
I can run the Reports() action directly via URL and it never slows like this and is quite fast for PDF generation. I am running it using the ActionAsPdf to obtain the binary to save to file system and send via email, which is the prescribed method of doing so for this library.
The behavior exists on both a local Windows 10 dev box and a remote Server 2008R2 Test box. .Net 4.5.1 on both boxes, default IIS on each.
Questions I have:
Any idea on what might cause this slow down and how to remedy it?
I ended up using UrlAsPdf() instead of ActionAsPdf() and it works. Seems there may be some issues with the ActionAsPdf() and I have filed a bug with Rotative project on GitHub. The ActionAsPdf() is still marked as beta, so hopefully it get's fixed in future versions or by the community.
In my case, I had to do few more tweaks along with using UrlAsPdf(). I have narrowed down the issue to the cookie collection that I was adding. So I tried just adding the cookie that I needed, and the issue was resolved. Following is the sample code that I have used.
var report = new UrlAsPdf(url);
Dictionary<string, string> cookieCollection = new Dictionary<string, string>();
foreach (var key in Request.Cookies.AllKeys)
{
if (Crypto.Hash("_user").Equals(key))
{
cookieCollection.Add(key, Request.Cookies.Get(key).Value);
break;
}
}
report.Cookies = cookieCollection;
report.FormsAuthenticationCookieName = FormsAuthentication.FormsCookieName;
Related
The issue:
We have an application written in C# that uses UIAutomation to get the current text (either selected or the word behind the carret) in other applications (Word, OpenOffice, Notepad, etc.).
All is working great on Windows 10, even up to 21H2, last update check done today.
But we had several clients informing us that the application is closing abruptly on Windows 11.
After some debugging I've seen some System.AccessViolationException thrown when trying to use the TextPatternRange.GetText() method:
System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'
What we've tried so far:
Setting uiaccess=true in manifest and signing the app : as mentionned here https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/350ceab8-436b-4ef1-8512-3fee4b470c0a/problem-with-manifest-and-uiaccess-set-to-true?forum=windowsgeneraldevelopmentissues => no changes (app is in C:\Program Files\
In addition to the above, I did try to set the level to "requireAdministrator" in the manifest, no changes either
As I've seen that it may come from a bug in Windows 11 (https://forum.emclient.com/t/emclient-9-0-1317-0-up-to-9-0-1361-0-password-correction-crashes-the-app/79904), I tried to install the 22H2 Preview release, still no changes.
Reproductible example
In order to be able to isolate the issue (and check it was not something else in our app that was causing the exception) I quickly made the following test (based on : How to get selected text of currently focused window? validated answer)
private void btnRefresh_Click(object sender, RoutedEventArgs e)
{
var p = Process.GetProcessesByName("notepad").FirstOrDefault();
var root = AutomationElement.FromHandle(p.MainWindowHandle);
var documentControl = new
PropertyCondition(AutomationElement.ControlTypeProperty,
ControlType.Document);
var textPatternAvailable = new PropertyCondition(AutomationElement.IsTextPatternAvailableProperty, true);
var findControl = new AndCondition(documentControl, textPatternAvailable);
var targetDocument = root.FindFirst(TreeScope.Descendants, findControl);
var textPattern = targetDocument.GetCurrentPattern(TextPattern.Pattern) as TextPattern;
string text = "";
foreach (var selection in textPattern.GetSelection())
{
text += selection.GetText(255);
Console.WriteLine($"Selection: \"{selection.GetText(255)}\"");
}
lblFocusedProcess.Content = p.ProcessName;
lblSelectedText.Content = text;
}
When pressing a button, this method is called and the results displayed in labels.
The method uses UIAutomation to get the notepad process and extract the selected text.
This works well in Windows 10 with latest update, crashes immediately on Windows 11 with the AccessViolationException.
On Windows 10 it works even without the uiaccess=true setting in the manifest.
Questions/Next steps
Do anyone know/has a clue about what can cause this?
Is Windows 11 way more regarding towards UIAutomation?
On my side I'll probably open an issue by Microsoft.
And one track we might follow is getting an EV and sign the app itself and the installer as it'll also enhance the installation process, removing the big red warnings. But as this is an app distributed for free we had not done it as it was working without it.
I'll also continue testing with the reproductible code and update this question should anything new appear.
I posted the same question on MSDN forums and got this answer:
https://learn.microsoft.com/en-us/answers/questions/915789/uiautomation-throws-accessviolationexception-on-wi.html
Using IUIautomation instead of System.Windows.Automation works on Windows 11.
So I'm marking this as solved but if anyone has another idea or knows what happens you're welcome to comment!
Recently, my application has crashed when trying to display a rather lengthy (but otherwise simple) HTML e-mail.
The crash was caused by mshtml.dll getting a stack overflow (exception code 0xc00000fd). Of note here is that this didn't throw an exception but it actually just crashed the program as a whole. The error was retrieved from the Windows event log.
In the process of debugging, I created a smaller sample solution to try and narrow down the issue. However, not only does it work fine in the sample solution, it behaves completely different from the main program despite running the same code even for the simplest of HTML strings.
The code is as follows:
var webBrowser1 = new System.Windows.Forms.WebBrowser();
webBrowser1.AllowNavigation = false;
webBrowser1.AllowWebBrowserDrop = false;
webBrowser1.Navigate("about:blank");
var doc = webBrowser1.Document.OpenNew(true);
doc.Write("<HTML><BODY>This is a new HTML document.</BODY></HTML>");
var count = doc.All.Count;
var html = doc.All[0].OuterHtml;
In the sample solution this evaluates to:
count = 4; // [HTML, HEAD, TITLE, BODY]
html = "<HTML><HEAD></HEAD>\r\n<BODY>This is a new HTML document.</BODY></HTML>";
Meanwhile in the main program it comes out to:
count = 3; // [HTML, HEAD, BODY]
html = "<html><head></head><body>This is a new HTML document.</body></html>";
These are small discrepancies but that is largely due to the simple HTML used. The one that causes the crash has rather significant differences.
I am absolutely stumped as to how the result can be so vastly different.
The documentation for HtmlDocument.Write(string) states that:
It is recommended that you write an entire valid HTML document using the Write method, including HTML and BODY tags. However, if you write just HTML elements, the Document Object Model (DOM) will supply these elements for you.
But I have no idea how the DomDocument is provided nor why they would be different in the first place. Both solutions are running in x64 Debug mode and Net-Framework 4.6.2.
Both load the module: C:\WINDOWS\assembly\GAC\Microsoft.mshtml\7.0.3300.0__b03f5f7f11d50a3a\Microsoft.mshtml.dll
How is it possible that these produce different results?!
Any and all help welcome.
Thanks in advance.
The difference in behavior stems from the registry entry as proposed by Jimi and linked here
HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION
To reiterate, in the above registry the main program had an entry "ApplicationFileName.exe"=dword:00002af9 while my new test-application didn't.
This, in and for itself, does not explain the crashing of mshtml.dll itself but since the question was about the difference in behavior I'll post this as the answer. The crash is most likely linked to the outdated version used by Visual Studio but I haven't yet had the chance to look into some of the proposed fixes for that.
I am trying to create a UI test in VS 2010 using IE 9 in IE 8 compatibilty mode however when trying to record an action recording many of the steps fail. Then when I manually code in the missing steps and try to fill in a log in form with a username and password I get an exception that says I have failed to perform an action on hidden control.
The UI Test code:
public void Recordedmethod()
{
BrowserWindow uILogInWindowsInternetWindow = this.UILogInWindowsInternetWindow;
HtmlHyperlink uILogInHyperlink = this.UILogInWindowsInternetWindow.UIHomePageDocument.UILogInHyperlink;
HtmlEdit uIUsernameEdit = this.UILogInWindowsInternetWindow.UILogInDocument1.UIUsernameEdit;
HtmlEdit uIPasswordEdit = this.UILogInWindowsInternetWindow.UILogInDocument1.UIPasswordEdit;
#endregion
// Go to web page 'http://localhost:15856/WebSite1/'
uILogInWindowsInternetWindow.NavigateToUrl(new System.Uri(this.RecordedMethodParams.UILogInWindowsInternetWindowUrl));
// Set flag to allow play back to continue if non-essential actions fail. (For example, if a mouse hover action fails.)
Playback.PlaybackSettings.ContinueOnError = true;
// Mouse hover 'Log In' link at (1, 1)
Mouse.Click(uILogInHyperlink);
// Reset flag to ensure that play back stops if there is an error.
Playback.PlaybackSettings.ContinueOnError = false;
// Type 'test' in 'Username:' text box
uIUsernameEdit.Text = this.RecordedMethodParams.UIUsernameEditText;
// The following element is no longer available: IE web control; Process Id [6320], window handle [3168166]
// Type '********' in 'Password:' text box
uIPasswordEdit.Password = this.RecordedMethodParams.UIPasswordEditPassword;
// The following element is no longer available: IE web control; Process Id [6320], window handle [3168166]
}
This is an issue linked to an Internet Explorer patch that was released in September.
KB2870699
This affects VS2010 and VS2012.
Microsoft released a patch that corrects the issue for VS2012 (and I've confirmed that it fixed the issue for me).
http://blogs.msdn.com/b/visualstudioalm/archive/2013/09/17/coded-ui-mtm-issues-on-internet-explorer-with-kb2870699.aspx
Currently the only workaround for VS2010 is to uninstall the patch (KB2870699); however, as with any sort of security patch you'll want to consider carefully whether pulling it is safe to do given your situation.
EDIT: This was not a fun bug for me to deal with. I had just upgraded to VS2012 from VS2010 and all of a sudden I found none of my previously functioning CodedUI tests working. I assumed it was an issue with VS2012 and after banging my head against the wall for the better part of a day I found out it was an issue with a patch. It was just my luck that I upgraded to 2012 at the same time the patch had been installed on my system. Good times!
There is actually an updated for VS 2012 to fix this issue
http://blogs.msdn.com/b/visualstudioalm/archive/2013/09/17/coded-ui-mtm-issues-on-internet-explorer-with-kb2870699.aspx
Hope this helps!
I was having the same problem with my coded ui test. It's an issue with VS-2012 i guess, i tried every update (installing/uninstalling them and everything..) nothing worked.
I tried VS-2013 Ultimate and it worked.
You can use exception handling to capture the error while still not having the test failed.
The test is failing because at the time it performs click action, the control is hidden.
try
{
//your code goes here
}
catch(FailedToPerformActionOnHiddenControlException e)
{
Console.WriteLine(e.Message);
}
I have inherited an application that runs small reports locally using Microsoft Web ReportViewer. Our application allows you to "Preview/Print" a report by clicking on a specific button that routes the user to a URL that allows them to download the report as a PDF. We have recently received the requirement to save these PDFs to the document table in our database. I have been able to get this to work successfully on localhost; however, when I publish the application to our IIS server, I get the following error:
System.Data.SqlClient.SqlException: Login failed for user 'Domain\Servername$'.
I've reviewed all of the sites that I could find involving this error (including this one) - most point to adding the server account to the SQL database; however, this shouldn't be an issue, since the button to preview/print the document is still functional and works as expected when the application is published and all of the data is held in a local object, which was previously pulled from the database (the model parameter below). The button and the auto-generation feature use the same two methods to create the PDF document(see below).
Here's some code:
public static byte[] CreatePDFDocument(DocumentTemplateType template, Request model)
{
Warning[] warnings;
string[] streamIds;
string mimeType = string.Empty;
string encoding = string.Empty;
string extension = string.Empty;
ReportViewer viewer = new ReportViewer();
viewer.ProcessingMode = ProcessingMode.Local;
viewer.LocalReport.ReportEmbeddedResource = "Xxx.Xxx.Bll.ReportViewerRDLCs." + template.RdlcFilename;
switch ((DocumentType)template.DocumentTypeId)
{
case eDocumentType.Report1:
viewer.LocalReport.SetParameters(GetForm1Parameters(model));
break;
/**
* Several other reports are in this switch. All reports have the
* same issue - all but one are removed for brevity.
*/
}
byte[] bytes = viewer.LocalReport.Render("PDF", null, out mimeType, out encoding, out extension, out streamIds, out warnings);
return bytes;
//return new byte[5] {5,6,7,8,9}; - used for troubleshooting.
}
public static List<ReportParameter> GetReport1Parameters(Request model)
{
List<ReportParameter> rptParams = new List<ReportParameter>();
//Start comment
rptParams.Add(new ReportParameter("EmployeeFullName", string.Format("{0:NN}", model.Employee)));
rptParams.Add(new ReportParameter("EmployeePhoneNumber", string.Format("{0:(###) ###-####}", Convert.ToInt64(model.Employee.PhoneNumber))));
rptParams.Add(new ReportParameter("HrchyShortDesc", model.Employee.HrchyShortDesc));
rptParams.Add(new ReportParameter("RequestDate", model.RequestDate.ToShortDateString()));
rptParams.Add(new ReportParameter("RequestRequested", model.RequestRequestType));
rptParams.Add(new ReportParameter("ReasonForRequest", model.RequestRequestReason));
rptParams.Add(new ReportParameter("LogNumber", model.CaseId));
if (!string.IsNullOrWhiteSpace(model.TimeSensitiveReason)) rptParams.Add(new ReportParameter("TimeSensitiveReason", model.TimeSensitiveReason));
var lastAction = model.LastActionOfType(WorkflowStateActionType.EmployeeConfirmation);
if (lastAction != null)
{
rptParams.Add(new ReportParameter("TodaysDate", lastAction.ActionDate.ToShortDateString()));
rptParams.Add(new ReportParameter("EmpConfirmed", "true"));
}
else rptParams.Add(new ReportParameter("TodaysDate", DateTime.Now.ToShortDateString()));
//end comment
return rptParams;
}
Through a lot of commenting in and out and pushes to our server, I've deduced the following:
From what I can tell, the error occurs on calling GetReport1Parameters. In the code above, I included a start and end comment - I've commented out everything in between, leaving only the list initialization and return statement (of an empty list) and still received the error.
I've commented out the call to GetReport1Parameters and returned a nonsensical byte array and didn't receive an Exception.
All functionality works fine on localhost and when I step through the functions, all of the variables seem to appear normal.
Things I've tried to do to remedy the situation:
1. Removed connection strings from the app.config, so that the application has to go to the web.config to get the correct strings (even though they were the same).
2. Commented in and out different sections of code to determine the problem area.
3. Tried calling the GetReport1Parameters method and returning null, leading to a null reference exception.
4. Tried calling the GetReport1Parameters with an empty parameter list, leading to the error mentioned above.
5. Tried running the report with no parameters (not even a blank list), got a ReportProcessingException for missing params.
Some additional information:
We use a service account for the application using impersonate identity in the web.config. That line is commented out on localhost, but is running on IIS.
All of other database interaction works correctly.
All of our database interaction is done using LINQ to SQL - model is an object based off of a database table, with some additional information that is calculated dynamically.
My desired outcome is that both the autogenerated documents and the preview/print documents both work. I have a feeling that this may be something simple that I'm overlooking, but I've already spent several hours today trying to fix this.
I can't think of any other pertinent information, but if you have questions I'll be more than happy to answer them.
Edit: Additional attempts to find solution:
Tried setting LINQ Deferred Loading equal to false. This caused more problems than it solved.
Implemented IReportServerCredentials and assigned the ReportViewer's ServerReport.ReportServerCredentials with the correct database credentials.
Assigned all pertinent report parameters to a Dictionary, and then called .ToString() on every object to ensure that it is pulled from the database. Then assigned those strings from the dictionary to the report parameters, so that ReportViewer should be receiving the data from the string pool, as opposed to pulling it from the database.
Even though you are using an ObjectDataSource to pass data to your report, Report Viewer will still invoke the Select method, which in turn could cause database access to occur. So even though it may seem that the login is unnecessary, you would need to dig into the data access methods you supplied with your ObjectDataSource to know for sure.
The error you are getting is being caused by a bug in Report Viewer 2010 that is describe in the following Microsoft Connect article:
ReportViewer.LocalReport.Render and ReportViewer.LocalReport.SetParameters changes ImpersonationLevel to None
Although the article mentions this problem should be fixed in Service Pack 1, it does not appear to be the case. I have not verified if this problem is fixed in Report Viewer 2012.
I worked around the problem by changing my data access layer to compare the current identity against the one in my HttpContext and restore it if necessary using the following code snippet:
System.Security.Principal.IIdentity id = System.Web.HttpContext.Current.User.Identity
if (id.Name != System.Security.Principal.WindowsIdentity.GetCurrent().Name)
{
context = (id as System.Security.Principal.WindowsIdentity).Impersonate()
}
I do this right before I connect to the database and undo it as soon as the connection is open.
I am not exactly thrilled with this workaround, mainly because now my data access layer is referencing the UI layer (System.Web).
I can successfully create an iteration path via:
var commonservice = collection.GetService<ICommonStructureService>();
// create new area path and iteration path
var iterationRoot = commonservice.GetNodeFromPath("\\MyTeamProject\\Iteration");
var newIterationPath = commonservice.CreateNode("my new sprint", iterationRoot.Uri);
However, when I try and assign this path to a work item and save it the field doesn't validate.
If I run the tests again (with the iteration already created) the same code succeeds.
Does anybody know how to make this work?
This fixed it for me:
WorkItemStore wis = (WorkItemStore)tfsTeamProjColl.GetService(typeof(WorkItemStore));
wis.RefreshCache();
wis.SyncToCache();
Maybe it will help someone.
I experienced exactly the same behavior, and unfortunately #JWC answer didn't help. The solution which works for me can be found by this link.
So, this is a quick summary in case the original answer gets lost.
The key point is to use WorkItemServer class. It lives in the Microsoft.TeamFoundation.WorkItemTracking.Proxy.dll assembly.
First of all, you create a WorkItemStore instance:
var store = collection.GetService<WorkItemStore>();
Then, create necessary iteration paths:
var commonservice = collection.GetService<ICommonStructureService>();
var iterationRoot = commonservice.GetNodeFromPath("\\MyTeamProject\\Iteration");
var newIterationPath = commonservice.CreateNode("my sprint", iterationRoot.Uri);
Next, refresh the cache in TFS (I suspect this is similar to pressing F5 in web interface):
var wiServer = collection.GetService<WorkItemServer>();
wiServer.SyncExternalStructures(WorkItemServer.NewRequestId(), commonservice.GetProjectFromName("MyTeamProject").Uri);
store.RefreshCache();
And finally, assign newly created work item to the newly created iteration:
var wi = new WorkItem(store.Projects["MyTeamProject"].WorkItemTypes["Product Backlog Item"]);
wi.Title = "Hello from API";
wi.Description = "This work item was created from API";
wi.Fields["Assigned To"].Value = "Yan Sklyarenko";
wi.IterationPath = FormatPath(commonservice.GetNode(newIterationPath).Path, "Iteration", "MyTeamProject");
wi.Save();
That's it! The method FormatPath translates the iteration path to the form required by the work item IterationPath field, that is from \MyTeamProject\Iteration\my sprint to MyTeamProject\my sprint.
Hope this can save some time.
NOTE: I run this towards TFS 2013.
You are likely running into a caching issue. Try clearing the cache after you create the iteration. A couple things you could try:
Get a new copy of the WorkItemStore.
Disconnect and reconnect to TFS
Check to see if there's a "refresh" method on either the WIS or on the TFS server objects. I've shut down my dev instance of TFS for the night, and I don't recall if there's anything like it.
If that's not quite it, post your code and I'll see if I can reproduce it.
I had the similar issue. I created Areapath and then created a query where the AreaPath was used. I did call store.RefreshCashe() but it did not work. Only in Debugger when I run store.RefreshCashe() two times manually.
Thanks "Yan Sklyarenko". I tried your Suggestion and it works fine (TFS Server 2012).