Using Specflow and Watin - have set the STA-thread, still get a System.Threading.ThreadStateException - watin

I'm writing UI-tests with Specflow and Watin.
I have done the following to ensure Watin to work
Setting the Thread.ApartmentState in the App.config
<configuration>
<configSections>
<section name="specFlow" type="TechTalk.SpecFlow.Configuration.ConfigurationSectionHandler, TechTalk.SpecFlow" />
<sectionGroup name="NUnit">
<section name="TestRunner" type="System.Configuration.NameValueSectionHandler"/>
</sectionGroup>
</configSections>
<NUnit>
<TestRunner>
<!-- Valid values are STA,MTA. Others ignored. -->
<add key="ApartmentState" value="STA" />
</TestRunner>
</NUnit>
</configuration>
In the Properties for InteropSHDocVw I've set the "Embeded Interop Types" to False and the "Copy Local" to True
My code looks like this...
code in () is because I'm not allowed to share credentials and urls to this site
The specflow feature
Feature: Company
In order to earn money
As a company
I want the suer to be able to shop our products
Scenario: Log In
Given I have navigated to (a companys test website)
And I have entered (a username) and (a password) as credentials
When I press Log in
Then then I should have the (permissions)
The teststeps written in Watin
using NUnit.Framework;
using System;
using TechTalk.SpecFlow;
using WatiN.Core;
namespace Projectname.Companyname.Specs
{
[Binding]
[RequiresSTA]
public class CompanySteps
{
IE browser = new IE();
[Given]
public void Given_I_have_navigated_to_URL(string url)
{
browser.GoTo(url);
}
[Given]
public void Given_I_have_entered_EMAIL_and_PASSWORD_as_credentials(string email, string password)
{
browser.TextField(Find.ByName("UserName")).TypeText(email);
browser.TextField(Find.ByText("Password")).TypeText(password);
}
[When]
public void When_I_press_Log_in()
{
browser.Button(Find.ByText("Log in »")).Click();
}
[Then]
public void Then_then_I_should_have_the_PERMISSION_permission(string permission)
{
browser.GoTo("the page where the permissions is showing as plain text");
Assert.IsTrue(browser.ContainsText(permission));
}
}
Now, my probelm, I've done all the things mentioned online to fix the STA or the Interop exceptions, but now when I run my Specflow/Watin test, I still get this exception for the STA thread:
System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
----> System.Threading.ThreadStateException : The CurrentThread needs to have it's ApartmentState set to ApartmentState.STA to be able to automate Internet Explorer.
Anyone who have had the same problem and has a solution? Have I forgotten any Code parts? is the syntax wrong somewhere?
Kindest regards and thanks in advance for your help.

Related

Net Core NLog.Web "aspnet-user-identity" is empty?

I was using "NLog.Extensions.Logging" for logging and need to log user identity and found that it is possible with "NLog.Web.AspNetCore". "nlog.config" file is configured to log the "aspnet-user-identity". However, when I look at logs, user identity part is always empty string, the other columns are look pretty good. Am I missing something?
A part of my configuration file is here:
<extensions>
<assembly="NLog.Web.AspNetCore" />
</extensions>
<parameter name="#identity" layout="${aspnet-user-identity}"/>
<logger name="*" minlevel="Trace" appendTo="database"/>
And an insert command insert a log to db with "#identity" parameter, but it is always empty like I said.
Accepted answer didn't worked for my case (using JwtSecurityToken on ASP.NET Core 3.1),
Later realized that I just forgot to add the ClaimTypes.Name on my JwtSecurityToken Claims.
Now its working and no need to register IHttpContextAccessor.
I think I have found the issue,
There was an breaking change, The IHttpContextAccessor service is not registered by default anymore. (See announcement)
So add in your startup.cs:
public void ConfigureServices(IServiceCollection Services)
{
//call this in case you need aspnet-user-authtype/aspnet-user-identity
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
I found this question while searching for "asp.net core nlog username". Eventually I found the solution and I am logging it here for posterity.
Problem
How do I include the currently logged in user's username in my NLog log messages?
Solution
I am using NLog inside of my ASP.NET Core web app. I tried using the ${aspnet-user-identity} layout renderer, but determined that the value was empty because we were using custom authentication.
After doing some digging, I figured out that I could access values stored as a ASP.NET Session variable from NLog. So, after I authenticated the user, I stuffed their username into a session variable and voila!
Here is the code I call after authenticating the user:
// Store username in session so we can access it from NLog logs.
httpContext.Session.SetString("NlogUser", contact.Username);
Here is what the layout renderer line in the nlog.config looks like
<parameter name="#identity" layout="${aspnet-session:variable=NlogUser}"/>
Here is the corresponding NLog documenation for the AspNetSession layout renderer.
If you recently upgraded ASP.NET Core you may have to configure NLog differently in program.cs:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.CaptureStartupErrors(true)
.UseIISIntegration()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.ConfigureLogging((hostingContext, logging) =>
{
//logging.AddNLog(); //<--- Can remove (NLog.Extensions.Logging)
})
;
})
.UseNLog(); // <--- Call UseNLog off of IHostBuilder (NLog.Web)
}
see https://github.com/NLog/NLog/wiki/Getting-started-with-ASP.NET-Core-3

Sitecore 7: "Clear on Index Update" not working?

Refer to this post for a description of the feature.
My HTML cache is enabled, and I have turned on "Clear on Index Update" for one of my Renderings.
However, the entry for my Rendering is NOT marked with any special token in the cache - I verified the cache content before and after using the rendering. This, of course, leads to the Clear() method in Sitecore.ContentSearch.Maintenance.IndexDependentHtmlCacheManager to not pick it up, making this feature useless.
I am on Sitecore 7.2 - is this a known bug?
You can override GenerateCacheKey processor (or add your own processor after that one) and update the key to include _#index.
Code below is for MVC. As #jammykam says, in WebForms key is added to cacheKey OOTB.
public class GenerateCustomCacheKey : GenerateCacheKey
{
protected override string GenerateKey(Rendering rendering, RenderRenderingArgs args)
{
Item renderingItem = rendering.RenderingItem.InnerItem;
var key = base.GenerateKey(rendering, args);
if (renderingItem["ClearOnIndexUpdate"].ToBool())
key += "_#index";
return key;
}
}
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<mvc.renderRendering>
<processor
type="My.Assembly.Namespace.GenerateCustomCacheKey, My.Assembly"
patch:instead="*[#type='Sitecore.Mvc.Pipelines.Response.RenderRendering.GenerateCacheKey, Sitecore.Mvc']" />
</mvc.renderRendering>
</pipelines>
</sitecore>
</configuration>
Ok, it turns out that this features is currently bugged on MVC, at least as of 16th of March 2015:
http://www.tarasalenin.com/caching-sitecore-mvc-renderings/
That's about it. There are workarounds, but in the meanwhile I sorted my problem in a different way. Posting this in case someone else happens to have the same problem.

compiler error "could not load embedded UI class EmbeddedUI.EmbeddedUI from assembly"

I'm trying to create an application using WIX 3.7 UI. If I assembly where my code is using. When compiling for .NET 4.0 I get the following error message:
SFXCA: Binding to CLR version v2.0.50727
Error: could not load embedded UI class EmbeddedUI.EmbeddedUI from assembly: CustomActions
I have tried different things in CustomAction.config. The current version is:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" />
</startup>
</configuration>
The class is implemented as follows:
public class HelloWorld : IEmbeddedUI
{
#region IEmbeddedUI Members
public bool Initialize(Session session, string resourcePath, ref InstallUIOptions internalUILevel)
{
System.Windows.Forms.MessageBox.Show("test256");
return true;
}
public MessageResult ProcessMessage(InstallMessage messageType, Record messageRecord, MessageButtons buttons, MessageIcon icon, MessageDefaultButton defaultButton)
{
return MessageResult.OK;
}
public void Shutdown()
{
}
#endregion
}
In the file Product.wxs:
<UI Id="Embedded">
<EmbeddedUI Id="MyTest" Name="CustomAction45CA.dll" SourceFile="..\CustomAction45\bin\Debug\CustomAction45CA.dll">
</EmbeddedUI>
</UI>
I'm using Visual Studio 2012.
When I switch from Framework in AssemblyProperties from 4.0 to 3.5 then everything works.
And the test with bootstrapper application works with framework 4.0.
I suspect that the MakeSfxCA.exe makes my dll broken. But I do not know what I can do. I have already experimented with MakeSfxCA.exe.config and x86 and x64.
I would be very grateful for any help
Error will be thrown only with EmbedddedUI. CustomAction from the same dll runs with message in installer log SFXCA: Binding to CLR version v4.0.30319

Ajax, jQuery, and JSONP

It seems like I can get JSON data from a different domain using jQuery's getJSON method (see: http://docs.jquery.com/Getjson). However, this works only for HTTP GET.
What if I needed to POST something and get the JSON response? How would I do that in jQuery/Ajax?
It is not possible to POST requests to a remote server from the client using jQuery alone as of version 1.6.1 in all browsers. If you attempt to make an XHttpRequest of any sort to a server in a different domain than the document, some browsers will simply fail to complete it. The JSONP requests to remote servers are handled by creating a script tag, the src for which is the API url with the query parameters added, including a callback method name. Because scripts can be loaded from any domain, this works, but it limits you to GET requests. The remote host returns the body of the script which is the callback invoked on the resulting javascript object. jQuery typically creates the callback function for you and from it calls the anonymous callback function you supply in the getJSON method parameters.
There are emerging standards, CORS and UMP (see also the comparison), that some browsers support but not in standardized ways (read IE does it differently). There are plugins to provide partial support for those browsers that do support CORS. No idea how well they work and they won't work unless the browser supports it.
The other answers aren't entirely true. This is possible if you have control over the server.
See:
W3C - Cross-Origin Resource Sharing
http://www.w3.org/TR/cors/
Essentially, the client sends a "pre-flight" OPTIONS HTTP request, and, if the correct response is received from the server, it continues with it's regular operations. (There are plenty of examples online... Unless you need me to, I won't get into the details).
I understand this may not work in all scenarios (for example, I'm not sure if IE5/5.5 supports this or not... but I believe IE6 does)... but if you're working on an HTML5 app, and you have control over the server, this could be a possibility for you.
NOTE: Just an aside - Given the option I'd prefer JSONP, of course. Less to go wrong.
EDIT: There seems to be a lot of confusion here, so let me give an example of how one might do this using .NET / WCF (I think some of this came from an article somewhere, and other parts of it were developed in house... so if some of it came from somewhere else, I apologize in advance for not giving the due credit):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace YourNamespaceHere
{
using System;
using System.Web;
using System.Collections;
public class CrossOriginModule : IHttpModule {
public String ModuleName {
get { return "CrossOriginModule"; }
}
public void Init(HttpApplication application) {
application.BeginRequest += (new EventHandler(this.Application_BeginRequest));
}
private void Application_BeginRequest(Object source, EventArgs e) {
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
CrossOriginHandler.SetAllowCrossSiteRequestOrigin(context);
}
public void Dispose()
{
}
}
public class CrossOriginHandler : IHttpHandler
{
#region IHttpHandler Members
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
//Clear the response (just in case)
ClearResponse(context);
//Checking the method
switch (context.Request.HttpMethod.ToUpper())
{
//Cross-Origin preflight request
case "OPTIONS":
//Set allowed method and headers
SetAllowCrossSiteRequestHeaders(context);
//Set allowed origin
//This happens for us with our module:
SetAllowCrossSiteRequestOrigin(context);
//End
context.Response.End();
break;
default:
context.Response.Headers.Add("Allow", "OPTIONS");
context.Response.StatusCode = 405;
break;
}
context.ApplicationInstance.CompleteRequest();
}
#endregion
#region Methods
protected void ClearResponse(HttpContext context)
{
context.Response.ClearHeaders();
context.Response.ClearContent();
context.Response.Clear();
}
protected void SetNoCacheHeaders(HttpContext context)
{
context.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
context.Response.Cache.SetValidUntilExpires(false);
context.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.Response.Cache.SetNoStore();
}
#endregion
public static void SetAllowCrossSiteRequestHeaders(HttpContext context)
{
string requestMethod = context.Request.Headers["Access-Control-Request-Method"];
context.Response.AppendHeader("Access-Control-Allow-Methods", "GET,POST");
//We allow any custom headers
string requestHeaders = context.Request.Headers["Access-Control-Request-Headers"];
if (!String.IsNullOrEmpty(requestHeaders))
context.Response.AppendHeader("Access-Control-Allow-Headers", requestHeaders);
}
public static void SetAllowCrossSiteRequestOrigin(HttpContext context)
{
string origin = context.Request.Headers["Origin"];
if (!String.IsNullOrEmpty(origin))
context.Response.AppendHeader("Access-Control-Allow-Origin", origin);
else
//This is necessary for Chrome/Safari actual request
context.Response.AppendHeader("Access-Control-Allow-Origin", "*");
}
}
}
And in the Web.config:
...
<system.webServer>
...
<modules runAllManagedModulesForAllRequests="true">
...
<add name="CrossOriginModule" preCondition="managedHandler" type="YOURNANMESPACEHERE.CrossOriginModule, ASSEMBLYNAME" />
</modules>
<handlers>
<add name="CrossOrigin" verb="OPTIONS" path="*" type="YOURNAMESPACEHERE.CrossOriginHandler, ASSEMBLYNAME" />
</handlers>
</system.webServer>
in short: JsonP is a cross-domain technique limited to GET request.
test.php
<?php fire query
$row = array();
while($queryresults){
$row['id'] = '$queryresults['idfield']';
$row['name'] = '$queryresults['namefield']';
$row['marks'] = '$queryresults['marksfield']';
$output[] = $row;
}
echo json_encode( $output ); //json array
?>
document ready
$.getJSON('test.php?query=query,function(data) {
$.each(enq_data, function(i,data){
$('.anydiv').append('<div class="row">'+data.id+data.name+data.marks+'</div>');
});
});

Renaming config files with Visual Studio setup project

My applications have a handful of config files, each one particular to the machine it's being deployed to (dev, production, etc.) I'm wanting to add them to the setup project, use radio buttons to select one and then have a script (or maybe custom action?) rename the selected files to connectionStrings.config, settings.config, etc.
Is this feasible/possible with a setup project?
To give you an idea, my configs might look like this:
DEV connectionStrings.config
PROD connectionStrings.config
After the user chooses DEV or PROD in the installer radiobutton UI, I would like the chosen config to be renamed to
connectionStrings.config
Considering it's a VS setup project, I have a feeling I'm asking for way too much and that I will get an interesting response as most setup project questions do :)
I created a setup project to set connection strings and i used the following which works perfectly for me.
Create a installer.cs file for the setup.
using System;
using System.Data.SqlClient;
using System.Xml;
using System.Configuration;
using System.Reflection;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Collections;
using System.Configuration.Install;
namespace YOURNAMESPACE
{
[RunInstaller(true)]
public partial class installer : System.Configuration.Install.Installer
{
public installer()
{
InitializeComponent();
}
public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install(stateSaver);
}
public override void Commit(IDictionary savedState)
{
base.Commit(savedState);
try
{
string DatabaseString1 = "FULL NAME OF CONNECTION STRING";
ConnectionConfigure(DatabaseString1);
}
catch (Exception e)
{
base.Rollback(savedState);
}
}
public override void Rollback(IDictionary savedState)
{
base.Rollback(savedState);
}
public override void Uninstall(IDictionary savedState)
{
base.Uninstall(savedState);
}
private void ConnectionConfigure(string DatabaseString)
{
string dataSource = "";
dataSource = "Provider="+ Context.Parameters["InitialCatalog"]+ ";" + "Data Source=" + Context.Parameters["DataSource"];
ExeConfigurationFileMap map = new ExeConfigurationFileMap();
string configFile = string.Concat(Assembly.GetExecutingAssembly().Location, ".config");
map.ExeConfigFilename = configFile;
System.Configuration.Configuration config = System.Configuration.ConfigurationManager.
OpenMappedExeConfiguration(map, System.Configuration.ConfigurationUserLevel.None);
string connectionsection = config.ConnectionStrings.ConnectionStrings
[DatabaseString].ConnectionString;
ConnectionStringSettings connectionstring = null;
if (connectionsection != null)
{
config.ConnectionStrings.ConnectionStrings.Remove(DatabaseString);
}
connectionstring = new ConnectionStringSettings(DatabaseString, dataSource);
config.ConnectionStrings.ConnectionStrings.Add(connectionstring);
config.Save(ConfigurationSaveMode.Modified, true);
ConfigurationManager.RefreshSection("connectionStrings");
}
}
}
Add project output to your setup project then begin to setup this setup project.
Right click setup project
Add text boxes and create the UI
Set custom actions
Create project output actions
Custom action properties
That is how i setup mine (I have attached screenshots to help explain my process but in short. Create setup project and installer.cs file. Add project output to setup project, add a UI so that the user can input a connection string and or provider for connection string, add custom actions so that the inputs can be read by the installer.cs file and then congratulations it should change the connection string.
Hope this helps.
I've come to the conclusion that this is impossible due to VS severely lacking on setup project configuration options. Instead I added a radio button control during the setup process and assigned the choices a variable name. In the file system I added all of my config files and then set conditions to each one. They referenced values to my radio button choices in order to copy during deployment.
I've done this many times, and basically I just install both files with different names. The application can ask the user which file to use, and change it anytime they want because many users don't know enough about the application to make this choice at install time.
You get interesting answers to setup questions like this because many people want to configure the application during the installation. Why not just let the setup install the files and have the app do its own configuration?

Resources