how to override the LocaleContext in Spring MVC - spring-mvc

I'm trying to customise the LocaleContext in Spring MVC to store some additional information.
I've set up a custom localeResolver, which works okay so far. But I'm not sure how to customise the locale context itself.
I wrote this class:
/**
* Creates a store aware localisation context
*/
public class SimpleStoreAwareLocaleContext extends SimpleTimeZoneAwareLocaleContext {
private Location location;
public SimpleStoreAwareLocaleContext(Locale locale, TimeZone timeZone) {
super(locale, timeZone);
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
}
But how do I get this to be the default LocaleContext on the LocaleContextHolder?
So when I call this, I want to get an instance of my locale context back..
LocaleContextHolder.getLocaleContext();
Is there a filter or something I need to override?
Also, just so I make sure my understanding is correct - is the LocaleContext thread local? So it should be different for each user right?
Thanks!

Ok, no answers, but I mostly have this working so here's what I did. I basically copy & pasted large amounts of the CookieLocaleResolver because there were private methods that I needed, and a few other reasons. But I came up with my own version of the cookie resolver, and modified the formatting in the cookie value to support more parameters:
/**
* <p>The custom locale resolver will also handle setting up the customer's local store in the
* locale context.</p>
*
*
*/
public class StoreLocaleResolver extends CookieLocaleResolver {
private static Logger logger = LogManager.getLogger(StoreLocaleResolver.class.getName());
private Location defaultLocation;
private Location location;
#Autowired
private LocationService locationService;
/**
* The name of the request attribute that holds the Location Information.
* <p>Only used for overriding a cookie value if the locale has been
* changed in the course of the current request!
* <p>Use {#code RequestContext(Utils).getTimeZone()}
* to retrieve the current time zone in controllers or views.
* #see org.springframework.web.servlet.support.RequestContext#getTimeZone
* #see org.springframework.web.servlet.support.RequestContextUtils#getTimeZone
*/
public static final String LOCAL_STORE_REQUEST_ATTRIBUTE_NAME = CookieLocaleResolver.class.getName() + ".LOCAL_STORE";
#Override
public void setLocaleContext(HttpServletRequest request, HttpServletResponse response, LocaleContext localeContext) {
//super.setLocaleContext(request, response, localeContext);
Locale locale = null;
TimeZone timeZone = null;
Location location = null;
if (localeContext != null) {
removeCookie(response);
if (localeContext instanceof SimpleStoreAwareLocaleContext) {
locale = localeContext.getLocale();
location = ((SimpleStoreAwareLocaleContext) localeContext).getLocation();
timeZone = ((TimeZoneAwareLocaleContext) localeContext).getTimeZone();
}
StringBuilder bud = new StringBuilder();
if (locale != null)
bud.append("locale:" + locale);
if (timeZone != null)
{
bud.append("::");
bud.append("timezone:" + timeZone.getID());
}
if (location != null)
{
bud.append("::");
bud.append("location:" + location.getExternalIdentifier());
}
String cookieValue = bud.toString();
addCookie(response, bud.toString());
}
else {
removeCookie(response);
}
request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME,
(locale != null ? locale: determineDefaultLocale(request)));
request.setAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME,
(timeZone != null ? timeZone : determineDefaultTimeZone(request)));
request.setAttribute(LOCAL_STORE_REQUEST_ATTRIBUTE_NAME,
(location != null ? location: determineDefaultLocalStore(request)));
}
#Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
SimpleStoreAwareLocaleContext localeContext = new SimpleStoreAwareLocaleContext(locale, null);
Location loc = (Location)request.getAttribute(StoreLocaleResolver.LOCAL_STORE_REQUEST_ATTRIBUTE_NAME);
if (loc != null)
{
localeContext.setLocation(loc);
}
setLocaleContext(request, response, (locale != null ? localeContext : null));
}
#Override
public Locale resolveLocale(HttpServletRequest request) {
parseLocaleCookieIfNecessary(request);
return (Locale) request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME);
}
#Override
public LocaleContext resolveLocaleContext(final HttpServletRequest request) {
parseLocaleCookieIfNecessary(request);
return new StoreAwareLocaleContext() {
#Override
public Locale getLocale() {
return (Locale) request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME);
}
#Override
public TimeZone getTimeZone() {
return (TimeZone) request.getAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME);
}
#Override
public Location getLocation() {
return (Location) request.getAttribute(LOCAL_STORE_REQUEST_ATTRIBUTE_NAME);
}
};
}
// copied from the parent class and extended to support parsing out the store location.
private void parseLocaleCookieIfNecessary(HttpServletRequest request) {
if (request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME) == null) {
// Retrieve and parse cookie value.
Cookie cookie = WebUtils.getCookie(request, getCookieName());
Locale locale = null;
TimeZone timeZone = null;
if (cookie != null) {
String value = cookie.getValue();
Map<String, String> params = new HashMap<String, String>();
String[] tokens1 = value.split("::");
for (String token: tokens1){
String[] tokens2 = token.split(":");
params.put(tokens2[0], tokens2[1]);
}
String localeString = params.get("locale");
String timezoneString = params.get("timezone");
String locationString = params.get("location");
if (localeString != null)
{
locale = StringUtils.parseLocaleString(localeString);
}
if (timezoneString != null)
{
timeZone = StringUtils.parseTimeZoneString(timezoneString);
}
if (locationString != null)
{
location = locationService.findForLocaleContext(locationString, false);
}
if (logger.isDebugEnabled()) {
logger.debug("Parsed cookie value [" + cookie.getValue() + "] into locale '" + locale +
"'" + (timeZone != null ? " and time zone '" + timeZone.getID() + "'" : ""));
}
}
request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME,
(locale != null ? locale: determineDefaultLocale(request)));
request.setAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME,
(timeZone != null ? timeZone : determineDefaultTimeZone(request)));
request.setAttribute(LOCAL_STORE_REQUEST_ATTRIBUTE_NAME,
(location != null ? location : determineDefaultLocalStore(request)));
}
}
/**
* Determine the default time zone for the given request,
* Called if no TimeZone cookie has been found.
* <p>The default implementation returns the specified default time zone,
* if any, or {#code null} otherwise.
* #param request the request to resolve the time zone for
* #return the default time zone (or {#code null} if none defined)
* #see #setDefaultTimeZone
*/
protected Location determineDefaultLocalStore(HttpServletRequest request) {
return getDefaultLocation();
}
#Override
protected Locale getDefaultLocale() {
logger.debug("Getting the default locale");
LocaleContextHolder.getLocaleContext();
return super.getDefaultLocale();
}
public Location getDefaultLocation() {
return defaultLocation;
}
public void setDefaultLocation(Location defaultLocation) {
this.defaultLocation = defaultLocation;
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
}
The other main class is an extended LocaleChangeInterceptor that allows me to change the local store by adding a parameter to any controller URL.
/**
* <p>The custom locale resolver will also handle setting up the customer's local store in the
* locale context.</p>
*
*
*/
#Component
public class StoreLocaleChangeInterceptor extends LocaleChangeInterceptor {
private static Logger logger = LogManager.getLogger(StoreLocaleChangeInterceptor.class.getName());
/**
* Default name of the store locale specification parameter: "store".
*/
public static final String DEFAULT_STORE_PARAM_NAME = "store";
private String storeParamName = DEFAULT_STORE_PARAM_NAME;
#Autowired
private LocationService locationService;
public String getStoreParamName() {
return storeParamName;
}
public void setStoreParamName(String storeParamName) {
this.storeParamName = storeParamName;
}
public LocationService getLocationService() {
return locationService;
}
public void setLocationService(LocationService locationService) {
this.locationService = locationService;
}
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws ServletException {
String newLocale = request.getParameter(getParamName());
String newStore = request.getParameter(this.storeParamName);
if (newStore != null || newLocale != null) {
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
if (localeResolver instanceof StoreLocaleResolver)
{
Location location = locationService.findByIdentifier(newStore);
if (location != null) {
((StoreLocaleResolver) localeResolver).setLocation(location);
request.setAttribute(StoreLocaleResolver.LOCAL_STORE_REQUEST_ATTRIBUTE_NAME, location);
}
if (newLocale != null)
{
localeResolver.setLocale(request, response, StringUtils.parseLocaleString(newLocale));
}else
{
Locale currentLocale = localeResolver.resolveLocale(request);
localeResolver.setLocale(request, response, currentLocale);
}
}
}
// Proceed in any case.
return true;
}
}
Then from the LocaleContextHolder I have to downcast to the context type (which is now an interface).
#ModelAttribute("myStore")
protected Location getCurrentStore() {
LocaleContext ctx = LocaleContextHolder.getLocaleContext();
if (StoreAwareLocaleContext.class.isAssignableFrom(ctx.getClass())){
return ((StoreAwareLocaleContext) ctx).getLocation();
}else
{
return null;
}
}

Related

ASP.NET Core 2.1 How to pass variables to TypeFilter

I have created this typefilter that is supposed to take 2 variables in order for it to send to a method that is linked to the filter. However, I am unable to attach my 2 variables for it to run.
public class RolesFilterAttribute : TypeFilterAttribute
{
public RolesFilterAttribute() : base(typeof(RolesFilterAttributeImpl))
{
}
private class RolesFilterAttributeImpl : IActionFilter
{
private readonly ValidateRoleClient validateRoleClient;
private string Role;
private string SecretKey;
public RolesFilterAttributeImpl(string Role, string SecretKey, ValidateRoleClient validateRoleClient)
{
this.validateRoleClient = validateRoleClient;
this.Role = Role;
this.SecretKey = SecretKey;
}
public void OnActionExecuted(ActionExecutedContext context)
{
if (context.HttpContext.Request.Cookies["Token"] != null || context.HttpContext.Request.Cookies["RefreshToken"] != null)
{
TokenViewModel tvm = new TokenViewModel
{
Token = context.HttpContext.Request.Cookies["Token"],
RefreshToken = context.HttpContext.Request.Cookies["RefreshToken"]
};
ValidateRoleViewModel vrvm = new ValidateRoleViewModel
{
Role = Role,
SecretKey = SecretKey,
Token = tvm
};
validateRoleClient.ValidateRole(vrvm);
}
}
public void OnActionExecuting(ActionExecutingContext context)
{
throw new NotImplementedException();
}
}
}
This is how I declare the filter and it compiles fine. However, I am not able to pass the required variables which are SecretKey and Role through it. Is my typefilter declared correctly?
[TypeFilter(typeof(RolesFilterAttribute))]
public IActionResult About()
{
return View();
}
Taken from the official documentation
[TypeFilter(typeof(AddHeaderAttribute),
Arguments = new object[] { "Author", "Steve Smith (#ardalis)" })]
public IActionResult Hi(string name)
{
return Content($"Hi {name}");
}

Android: Prevent notfying Parent/Descendent uri's in ContentProvider while using CursorLoader?

I have a CursorLoader that observes a directory with this URI:
uriDirectory = content://com.myapp.stocks/stocks
and another CursorLoader that observes an item with this URI:
uriItem = content://com.myapp.stocks/stocks/GOOG
When I update uriItem and call getContext().getContentResolver().notifyChange(uriItem , null); in my ContentProvider, how can I prevent it from notifying uriDirectory as well?
Thanks!
Edit: So my solution so far is just to have a boolean that is set to true when I notify a uriItem. Then when it notifies the parent, uriDirectory, it will see that the boolean is true and won't perform any operations. After, I set the boolean back to false.
You can write your own CursorLoader. The default cursor loaders register a content observer via Cursor.RegisterContentObserver(ContentObserver observer). Instead, we want to use registerContentObserver(Uri uri, boolean notifyForDescendants, ContentObserver observer).
I'm not sure if you are using the support library CursorLoader but for the greatest applicability, that's what I'm using.
The only changes from the stock android versions are in loadInBackground(). You should create an entire class instead of just extending android's and overriding loadInBackground because it protects you from future changes made to Android. Be advised that this will not use any notification url you set for the cursor in your ContentProvider unless you the device is KitKat or newer
Uri notificationUri;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
notificationUri = cursor.getNotificationUri();
} else {
notificationUri = mUri;
}
getContext().getContentResolver().registerContentObserver(
notificationUri != null ? notificationUri : mUri,
false, //don't notify for descendants
mObserver
);
Full class descendantChangeIgnoringCursorLoader.java:
package com.innomatixdata.busscan.utils;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.ContentResolverCompat;
import android.support.v4.content.Loader;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Arrays;
public class DescendantChangeIgnoringCursorLoader extends AsyncTaskLoader<Cursor> {
final Loader.ForceLoadContentObserver mObserver;
Uri mUri;
String[] mProjection;
String mSelection;
String[] mSelectionArgs;
String mSortOrder;
Cursor mCursor;
android.support.v4.os.CancellationSignal mCancellationSignal;
/* Runs on a worker thread */
#Override
public Cursor loadInBackground() {
synchronized (this) {
if (isLoadInBackgroundCanceled()) {
throw new android.support.v4.os.OperationCanceledException();
}
mCancellationSignal = new android.support.v4.os.CancellationSignal();
}
try {
Cursor cursor = ContentResolverCompat.query(getContext().getContentResolver(),
mUri, mProjection, mSelection, mSelectionArgs, mSortOrder,
mCancellationSignal);
if (cursor != null) {
try {
// Ensure the cursor window is filled.
cursor.getCount();
Uri notificationUri;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
notificationUri = cursor.getNotificationUri();
} else {
notificationUri = mUri;
}
getContext().getContentResolver().registerContentObserver(
notificationUri != null ? notificationUri : mUri,
false, //don't notify for descendants
mObserver
);
} catch (RuntimeException ex) {
cursor.close();
throw ex;
}
}
return cursor;
} finally {
synchronized (this) {
mCancellationSignal = null;
}
}
}
#Override
public void cancelLoadInBackground() {
super.cancelLoadInBackground();
synchronized (this) {
if (mCancellationSignal != null) {
mCancellationSignal.cancel();
}
}
}
/* Runs on the UI thread */
#Override
public void deliverResult(Cursor cursor) {
if (isReset()) {
// An async query came in while the loader is stopped
if (cursor != null) {
cursor.close();
}
return;
}
Cursor oldCursor = mCursor;
mCursor = cursor;
if (isStarted()) {
super.deliverResult(cursor);
}
if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
oldCursor.close();
}
}
/**
* Creates an empty unspecified CursorLoader. You must follow this with
* calls to {#link #setUri(Uri)}, {#link #setSelection(String)}, etc
* to specify the query to perform.
*/
public DescendantChangeIgnoringCursorLoader(Context context) {
super(context);
mObserver = new Loader.ForceLoadContentObserver();
}
/**
* Creates a fully-specified CursorLoader. See {#link ContentResolver#query(Uri, String[],
* String, String[], String) ContentResolver.query()} for documentation on the meaning of the
* parameters. These will be passed as-is to that call.
*/
public DescendantChangeIgnoringCursorLoader(Context context, Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
super(context);
mObserver = new Loader.ForceLoadContentObserver();
mUri = uri;
mProjection = projection;
mSelection = selection;
mSelectionArgs = selectionArgs;
mSortOrder = sortOrder;
}
/**
* Starts an asynchronous load of the contacts list data. When the result is ready the callbacks
* will be called on the UI thread. If a previous load has been completed and is still valid
* the result may be passed to the callbacks immediately.
*
* Must be called from the UI thread
*/
#Override
protected void onStartLoading() {
if (mCursor != null) {
deliverResult(mCursor);
}
if (takeContentChanged() || mCursor == null) {
forceLoad();
}
}
/**
* Must be called from the UI thread
*/
#Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
#Override
public void onCanceled(Cursor cursor) {
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
}
#Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
if (mCursor != null && !mCursor.isClosed()) {
mCursor.close();
}
mCursor = null;
}
public Uri getUri() {
return mUri;
}
public void setUri(Uri uri) {
mUri = uri;
}
public String[] getProjection() {
return mProjection;
}
public void setProjection(String[] projection) {
mProjection = projection;
}
public String getSelection() {
return mSelection;
}
public void setSelection(String selection) {
mSelection = selection;
}
public String[] getSelectionArgs() {
return mSelectionArgs;
}
public void setSelectionArgs(String[] selectionArgs) {
mSelectionArgs = selectionArgs;
}
public String getSortOrder() {
return mSortOrder;
}
public void setSortOrder(String sortOrder) {
mSortOrder = sortOrder;
}
#Override
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
super.dump(prefix, fd, writer, args);
writer.print(prefix); writer.print("mUri="); writer.println(mUri);
writer.print(prefix); writer.print("mProjection=");
writer.println(Arrays.toString(mProjection));
writer.print(prefix); writer.print("mSelection="); writer.println(mSelection);
writer.print(prefix); writer.print("mSelectionArgs=");
writer.println(Arrays.toString(mSelectionArgs));
writer.print(prefix); writer.print("mSortOrder="); writer.println(mSortOrder);
writer.print(prefix); writer.print("mCursor="); writer.println(mCursor);
}
}

error occured when adding anotation to the java class

Multiple markers at this line
- Repository cannot be resolved to a type
- The attribute value is undefined for the annotation type
Error gets when trying to add #Repository("loginDAO") to the loginDAOImpl.java. I don't use maven.
#Repository("loginDAO")
public class LoginDAOImpl implements LoginDAO {
#Resource(name="sessionFactory")
protected SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
protected Session getSession(){
return sessionFactory.openSession();
}
public boolean checkLogin(String userName, String userPassword) {
System.out.println("In Check login");
Session session = sessionFactory.openSession();
boolean userFound = false;
//Query using Hibernate Query Language
String SQL_QUERY =" from Users as o where o.userName=? and o.userPassword=?";
Query query = session.createQuery(SQL_QUERY);
query.setParameter(0,userName);
query.setParameter(1,userPassword);
List list = query.list();
if ((list != null) && (list.size() > 0)) {
userFound= true;
}
session.close();
return userFound;
}

Trying to test a HttpServletResponseWrapper inside a ResponseHeaderFilter with MockHttpServletResponse

I am trying to unit test the below ResponseHeaderFilter but find that this unit test fails:
#Test
public void testDoFilterWithOmmissableInitParameters_ETag()
throws IOException, ServletException {
// Add allowableUserAgents initParameters
MockFilterConfig filterConfig = new MockFilterConfig();
filterConfig.addInitParameter("allowableUserAgents", "avaya");
// Add allowableUserAgents initParameters
filterConfig.addInitParameter(OMIT_KEY, OMIT_VALUE);
// Set user-agent
request.addHeader("user-agent", "avaya");
response.addHeader("ETag", "someEtagHash");
filter.init(filterConfig);
filter.doFilter(request, response, chain);
// THIS ASSERTION FAILS:
assertThat((String)response.getHeader("ETag"), is(nullValue()));
}
Specifically, the setHeader() method when I run this in debug mode is NEVER called:
chain.doFilter(request,
new HttpServletResponseWrapper(response) {
public void setHeader(String name, String value) {
//if (!(name != null && omitHeaders.contains(name.toUpperCase()))) {
if (name != null && omitHeaders.contains(name)) {
super.setHeader(name, value);
}
}
});
The debugger gets to the line for new HttpServletResponseWrapper(response) but does not actually execute the setHeader method.
here is the entire class itself:
public class ResponseHeaderFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(ResponseHeaderFilter.class);
Map<String, String> additionalHeaders = new HashMap<String, String>();
Set<String> omitHeaders = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
Set<String> allowableUserAgents = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
boolean allowFromAllUserAgents = false;
public void doFilter(final ServletRequest request,
final ServletResponse res,
final FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
String userAgent = ((HttpServletRequest) request).getHeader("user-agent");
if (allowFromAllUserAgents
|| (userAgent != null && allowableUserAgents.contains(userAgent))
) {
logger.debug("apply ResponseHeader rules for user agent [{}]", userAgent);
for (Map.Entry<String, String> entry : additionalHeaders.entrySet()) {
response.addHeader(entry.getKey(), entry.getValue());
}
chain.doFilter(request,
new HttpServletResponseWrapper(response) {
public void setHeader(String name, String value) {
//if (!(name != null && omitHeaders.contains(name.toUpperCase()))) {
if (name != null && omitHeaders.contains(name)) {
super.setHeader(name, value);
}
}
});
} else {
logger.debug("User agent [{}] is not an allowable agent for this filter", userAgent);
chain.doFilter(request, res);
}
}
/**
* Called once during start-up
*
* #param filterConfig for Filter configuration
*/
public void init(final FilterConfig filterConfig) {
logger.info("*** ResponseHeaderFilter.init() ***");
// set the provided HTTP response parameters
for (Enumeration e = filterConfig.getInitParameterNames(); e.hasMoreElements(); ) {
String headerName = (String) e.nextElement();
String headerValue = filterConfig.getInitParameter(headerName);
// Add the list of allowable user-agents
// cannot be null: if (headerName != null) {
if (headerName.equalsIgnoreCase("allowableUserAgents")) {
// omit
parseToUpperCaseElements(headerValue, allowableUserAgents);
logger.debug("allowable user-agent's {}", allowableUserAgents);
} else if (headerName.equalsIgnoreCase("allowFromAllUserAgents")) {
allowFromAllUserAgents = Boolean.parseBoolean(headerValue);
logger.debug("allowFromAllUserAgents {}", allowFromAllUserAgents);
} else if (headerName.equalsIgnoreCase("omit")) {
parseToUpperCaseElements(headerValue, omitHeaders);
logger.debug("Omit headers {}", omitHeaders);
} else {
additionalHeaders.put(headerName, headerValue);
logger.debug("adding header [{}] with value [{}]", headerName, headerValue);
}
//}
}
}
protected final void parseToUpperCaseElements(final String str, final Set<String> elementKeys) {
String[] words = str.split(",");
for (String s : words) {
elementKeys.add(s.trim().toUpperCase());
}
}
public void destroy() {
logger.debug("destroy");
}
}
This filter DOES actually work when running and DOES remove the ETag header, but when I am trying to use Cobertura for code coverage, that method is not tested.
Actually the code you are testing ResponseHeaderFilter only adds or register an anonymous HttpServletResponseWrapper in the FilterChain :
chain.doFilter(request, new HttpServletResponseWrapper(response) {
public void setHeader(String name, String value) { ... }
});
And the FilterChain is executed by the container itself. Your test code does nothing but passing a FilterChain reference.
I don't know the real type of your FilterChain in your test, but instead of asserting that the tag got removed (assertThat((String)response.getHeader("ETag"), is(nullValue()));) I would split your test in two different test.
Replace the anonymous HttpServletResponseWrapper by a full type that can be called EtagRemoverHttpServletResponseWrapper and make a unit test that will actually assert that on wrapper.setHeader(...) it etag header is omitted.
The first on your ResponseHeaderFilter which will assert that the chain contains a reference of type ETagRemoverHttpServletResponseWrapper
Hope that helps.

Structuremap error when using HttpContextBase in constructor

I am building a ASP.NET MVC 2.0 app on .NET 4.0 and am using Structuremap 2.6.1 for IoC. I recently added a ICookie and Cookie class, the Cookie class takes HttpContextBase as a constructor parameter (See below) and now when I run my app I get this error :No Default Instance defined for PluginFamily System.Web.HttpContextBase.
I have used this method before in another MVC app with the same stack but did not get this error. Am I missing something? If I do need to add some mapping code for HttoContextBase in my structuremap configuration file what would I use?
And help would be great!!!
Cookie.cs
public class Cookie : ICookie
{
private readonly HttpContextBase _httpContext;
private static bool defaultHttpOnly = true;
private static float defaultExpireDurationInDays = 1;
private readonly ICryptographer _cryptographer;
public Cookie(HttpContextBase httpContext, ICryptographer cryptographer)
{
Check.Argument.IsNotNull(httpContext, "httpContext");
Check.Argument.IsNotNull(cryptographer, "cryptographer");
_cryptographer = cryptographer;
_httpContext = httpContext;
}
public static bool DefaultHttpOnly
{
[DebuggerStepThrough]
get { return defaultHttpOnly; }
[DebuggerStepThrough]
set { defaultHttpOnly = value; }
}
public static float DefaultExpireDurationInDays
{
[DebuggerStepThrough]
get { return defaultExpireDurationInDays; }
[DebuggerStepThrough]
set
{
Check.Argument.IsNotZeroOrNegative(value, "value");
defaultExpireDurationInDays = value;
}
}
public T GetValue<T>(string key)
{
return GetValue<T>(key, false);
}
public T GetValue<T>(string key, bool expireOnceRead)
{
var cookie = _httpContext.Request.Cookies[key];
T value = default(T);
if (cookie != null)
{
if (!string.IsNullOrWhiteSpace(cookie.Value))
{
var converter = TypeDescriptor.GetConverter(typeof(T));
try
{
value = (T)converter.ConvertFromString(_cryptographer.Decrypt(cookie.Value));
}
catch (NotSupportedException)
{
if (converter.CanConvertFrom(typeof(string)))
{
value = (T)converter.ConvertFrom(_cryptographer.Decrypt(cookie.Value));
}
}
}
if (expireOnceRead)
{
cookie = _httpContext.Response.Cookies[key];
if (cookie != null)
{
cookie.Expires = DateTime.Now.AddDays(-100d);
}
}
}
return value;
}
public void SetValue<T>(string key, T value)
{
SetValue(key, value, DefaultExpireDurationInDays, DefaultHttpOnly);
}
public void SetValue<T>(string key, T value, float expireDurationInDays)
{
SetValue(key, value, expireDurationInDays, DefaultHttpOnly);
}
public void SetValue<T>(string key, T value, bool httpOnly)
{
SetValue(key, value, DefaultExpireDurationInDays, httpOnly);
}
public void SetValue<T>(string key, T value, float expireDurationInDays, bool httpOnly)
{
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
string cookieValue = string.Empty;
try
{
cookieValue = converter.ConvertToString(value);
}
catch (NotSupportedException)
{
if (converter.CanConvertTo(typeof(string)))
{
cookieValue = (string)converter.ConvertTo(value, typeof(string));
}
}
if (!string.IsNullOrWhiteSpace(cookieValue))
{
var cookie = new HttpCookie(key, _cryptographer.Encrypt(cookieValue))
{
Expires = DateTime.Now.AddDays(expireDurationInDays),
HttpOnly = httpOnly
};
_httpContext.Response.Cookies.Add(cookie);
}
}
}
IocMapping.cs
public class IoCMapping
{
public static void Configure()
{
var connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["ProjectName.Core.Properties.Settings.ProjectNameConnectionString"].ConnectionString;
MappingSource mappingSource = new AttributeMappingSource();
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.Assembly("ProjectName.Core");
scan.Assembly("ProjectName.WebUI");
scan.WithDefaultConventions();
});
x.For<IUnitOfWork>().HttpContextScoped().Use<UnitOfWork>();
x.For<IDatabase>().HttpContextScoped().Use<Database>().Ctor<string>("connection").Is(connectionString).Ctor<MappingSource>("mappingSource").Is(mappingSource);
x.For<ILogger>().Singleton().Use<NLogLogger>();
x.For<ICacheManager>().Singleton().Use<CacheManager>().Ctor<System.Web.Caching.Cache>().Is(HttpRuntime.Cache);
x.For<IEmailSender>().Singleton().Use<EmailSender>();
x.For<IAuthenticationService>().HttpContextScoped().Use<AuthenticationService>();
x.For<ICryptographer>().Use<Cryptographer>();
x.For<IUserSession>().HttpContextScoped().Use<UserSession>();
x.For<ICookie>().HttpContextScoped().Use<Cookie>();
x.For<ISEORepository>().HttpContextScoped().Use<SEORepository>();
x.For<ISpotlightRepository>().HttpContextScoped().Use<SpotlightRepository>();
x.For<IContentBlockRepository>().HttpContextScoped().Use<ContentBlockRepository>();
x.For<ICatalogRepository>().HttpContextScoped().Use<CatalogRepository>();
x.For<IPressRoomRepository>().HttpContextScoped().Use<PressRoomRepository>();
x.For<IEventRepository>().HttpContextScoped().Use<EventRepository>();
x.For<IProductRegistrationRepository>().HttpContextScoped().Use<ProductRegistrationRepository>();
x.For<IWarrantyRepository>().HttpContextScoped().Use<WarrantyRepository>();
x.For<IInstallerRepository>().HttpContextScoped().Use<InstallerRepository>();
x.For<ISafetyNoticeRepository>().HttpContextScoped().Use<SafetyNoticeRepository>();
x.For<ITradeAlertRepository>().HttpContextScoped().Use<TradeAlertRepository>();
x.For<ITestimonialRepository>().HttpContextScoped().Use<TestimonialRespository>();
x.For<IProjectPricingRequestRepository>().HttpContextScoped().Use<ProjectPricingRequestRepository>();
x.For<IUserRepository>().HttpContextScoped().Use<UserRepository>();
x.For<IRecipeRepository>().HttpContextScoped().Use<RecipeRepository>();
});
LogUtility.Log.Info("Registering types with StructureMap");
}
}
I believe you would need to register the HttpContextBase on every request in your Begin_Request handler like so:
For<HttpContextBase>().Use(() => new HttpContextWrapper(HttpContext.Current));
Update: Make sure you register a lambda, otherwise you StructureMap will store the HttpContext available at registration time as a singleton.

Resources