Tag: .NET
How to create a new instance of a dependency inject object

How to create a new instance of a dependency inject object

I decided to write this post after seeing it done wrong on a number of occasions and also not finding many great examples of how it should be done. Most articles of DI or IOC tend to focus on objects such as a logger being injected and then calling functions on that object.

Take for instance, this example in the Simple Injector documentation:

1using System;
2using System.Web.Mvc;
3
4public class UserController : Controller {
5 private readonly IUserRepository repository;
6 private readonly ILogger logger;
7
8 public UserController(IUserRepository repository, ILogger logger) {
9 this.repository = repository;
10 this.logger = logger;
11 }
12
13 [HttpGet]
14 public ActionResult Index(Guid id) {
15 this.logger.Log("Index called.");
16 IUser user = this.repository.GetById(id);
17 return this.View(user);
18 }
19}

Here we can see the implementation of IUserRepository and ILogger get passed in the constructor and are then used in the Index method.

However what would the example be if we wanted to create a new user and call the user repository to save it? Creating a new instance of IUser from our controller becomes an issue as we don't know what the implementation of IUser is.

The incorrect implementation I usually see is someone adding a reference to the implementation and just creating a new instance of it. A bit like this:

1public class UserController : Controller {
2 [HttpPost]
3 public ActionResult SaveUser(UserDetails newUserInfo) {
4
5 IUser user = new User;
6 user.FirstName = newUserInfo.FirstName;
7 user.LastName = newUserInfo.LastName;
8 this.repository.SaveUser(user);
9 return this.View(user);
10 }
11}

This will work, but fundamentally defeats the point of using dependency injection as we now have a dependency on the user objects specific implementation.

The solution I use is to add a factory method to our User Repository which takes care of creating a User object.

1public class UserRepository : IUserRepository {
2 public User CreateUser() {
3 return new User();
4 }
5}

Responsibility of creating the object now remains with its implementation and our controller no longer needs to have a reference to anything other than the interface.

1public class UserController : Controller {
2 [HttpPost]
3 public ActionResult SaveUser(UserDetails newUserInfo) {
4
5 IUser user = this.repository.CreateUser();
6 user.FirstName = newUserInfo.FirstName;
7 user.LastName = newUserInfo.LastName;
8 this.repository.SaveUser(user);
9 return this.View(user);
10 }
11}
Redirect to https using URL Rewrite

Redirect to https using URL Rewrite

There's always been reasons for pages to be served using https rather than http, such as login pages, payment screens etc. Now more than ever it's become advisable to have entire sites running in https. Server speeds have increased to a level where the extra processing involved in encrypting page content is less of a concern, and Google now also gives a boost to a pages page ranking in Google (not necessarily significant, but every little helps).

If all your pages work in https and http you'll also need to make sure one does a redirect to the other, otherwise rather than getting the tiny page rank boost from Google, you'll be suffering from having duplicate pages on your site.

Redirecting to https with URL Rewrite

To set up a rule to redirect all pages from is relatively simple, just add the following to your IIS URL Rewrite rules.

1<rule name="Redirect to HTTPS" stopProcessing="true">
2 <conditions>
3 <add input="{HTTPS}" pattern="^OFF$" />
4 </conditions>
5 <action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" appendQueryString="false" />
6</rule>

The conditions will ensure any page not on https will be caught and the redirect will do a 301 to the same page but on https.

301 Moved Permanently or 303 See Other

I've seen some posts/examples and discussions surrounding if the redirect type should be a 301 or a 303 when you redirect to https.

Personally I would choose 301 Moved Permanently as you want search engines etc to all update and point to the new url. You've decided that your url from now on should be https, it's not a temporary redirection and you want any link ranking to be transfered to the new url.

Excluding some URL's

There's every chance you don't actually want every url to redirect to https. You may have a specific folder that can be accessed on either for compatibility with some other "thing". This can be accomplished by adding a match rule that is negated. e.g.

1<rule name="Redirect to HTTPS" stopProcessing="true">
2 <match url="images" negate="true" />
3 <conditions>
4 <add input="{HTTPS}" pattern="^OFF$" />
5 </conditions>
6 <action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" appendQueryString="false" />
7</rule>

In this example any url with the word images in would be excluded from the rewrite rule.

Sitecore: Extend profile matching over multiple visits

In Sitecore, to gain a better understanding of our visitors interests we have the ability to define Profile Keys and Cards to tag our content with. As our visitors navigate through the site, this data is used by Sitecore to build a profile of the visitor. A pre-defined Pattern Card that most resembles the visitors profile is then assigned to the visitor which can be used as the basis of selecting the content that should be displayed on a page for that visitor.

However what this doesn't do is carry the visitors profile over multiple sessions. Each time a visitor comes back to the site within a new session, the visitors profile key values are reset back to zero.

So what's Sitecore actually doing?

Before working out how to carry this information between visits, lets look at how a profile is actually being created.

If we look in the Profiles table within the Analytics database we can see the profile data that’s been recorded for a visitors visit.

The Pattern Values column contains the current profile key scores for each key the visitor has a score for. e.g.

background=40;scope=50

If the visitor was to visit a page which has scope score of 5 and background score of 10 these values would be added to the visitors current key scores. e.g.

background=50;scope=55

When a pattern card is assigned, the card with the closest shape of keys is chosen. e.g. If the visitor has a high value for background and low value for scope they will be assigned a pattern card with similar proportional key values.

How do we extend this over multiple visits?

So the easiest way to carry the visit information from one visit to the next would be to simply copy the profile key values from the last session to the next. The code for this would look similar to the following:

1var currentVisitIndex = Tracker.CurrentVisit.VisitorVisitIndex;
2
3if (currentVisitIndex &lt;= 1 || !Tracker.CurrentVisit.Profiles.Any())
4{
5 return;
6}
7
8var previousProfiles = Tracker.Visitor.GetVisit(currentVisitIndex - 1, VisitLoadOptions.All).Profiles;
9
10foreach (var profile in previousProfiles)
11{
12 var currentProfile = Tracker.CurrentVisit.GetOrCreateProfile(profile.ProfileName);
13
14 currentProfile.BeginEdit();
15
16 foreach (var ProfileKey in profile.Values)
17 {
18 currentProfile.Score(ProfileKey.Key, ProfileKey.Value);
19 }
20 currentProfile.UpdatePattern();
21
22 currentProfile.EndEdit();
23}

Now the visitors profile is how it was when they left and crucially we can use this data to personalize the sites homepage for the visitor.

So why shouldn't we do this?

As simple as this is, it comes with one potentially massive downside. If we go back to the way the profile values are built up they key values are essentially just being accumulated. Each time the visitor visits an item with a background score of 10, the visitors background profile key score in increased by 10.

Our visitors are humans going through different stages of there life, with constantly changing jobs and interests. There's nothing to ever reduce a profile keys score other than the fact everything is normally zeroed on each visit. By copying the data from the last visit on the start of the next this would never happen and the profile key's will continue to count up forever. The key value obtained from an item viewed 2 months ago would counted as just as important as the value from another key viewed on an item today.

So if you were running a travel site and a visitor looked at summer holidays for 3 weeks they will have a profile highly weighted towards summer holidays. If they then started to look at winter holidays we wouldn't want them to have to look at winter holidays for 3 weeks just to have an even likeness of summer and winter.

Overcoming this issue isn't so simple and largely depends on your business needs. If your visitors interests could change each week then you need something that will degrade the old visit data values quickly. Whereas if your trying to differentiate between people that are in a 2 week vs 6 month buying pattern, you need to retain that data a lot longer.

Some things we can do when copying the data from the visitors previous profile though could include:

  • Halving the profile scores, or reducing by a different factor. This would reduce the importance of values obtained on previous visits. So if a visitor received a 10 on the first visit, it would be worth 5 on the second, 2.5 on the third etc
  • Look at the date of the last visit. Is it to old to be relevant still or can we use the age to determine what factor we should reduce the scores by
  • Look at a combination of multiple last visits to establish what the recent scores were

All these ideas though need to be used on conjunction with what your trying to profile. If it's age then you know people are going to get older. If it's an interest that will change frequently then you know the data needs to degrade quickly, but if it's male/female then that doesn't necessarily need to degrade at all.