I det här inlägget beskrivs hur du kan skapa en webbplats med flera domännamn i ASP.NET Core. En webbplats med flera domäner är billigare att hosta, lättare att underhålla och lättare att administrera jämfört med flera webbplatser. För en multidomän-webbplats kan du anpassa innehåll, språk och design för varje domän.
En multidomän-webbplats gör att du kan översätta din webbplats till olika språk och/eller ha flera butiker på en webbplats genom att koppla produkter till domäner. Du kan koppla dina modeller till en domän, till ett språk och/eller till en butik. Du kan kombinera kopplingar, vissa modeller kan kopplas till ett språk och vissa modeller kan kopplas till en domän.
En webbplats med flera domäner lagrar domänmodeller i en databas, hämtar den aktuella domänen vid en begäran och använder egenskaperna i domänmodellen för att hämta andra resurser (exempelvis: statiska texter, en sida och/eller en produkt).
Modell
En domänmodell innehåller de egenskaper som behövs för att korrekt ansluta resurser till domännamnet. Egenskapen domain_name används för att hitta den aktuella domänen.
public class WebDomain
{
#region Variables
public Int32 id { get; set; }
public string website_name { get; set; }
public string domain_name { get; set; }
public string web_address { get; set; }
public Int32 front_end_language { get; set; }
public Int32 back_end_language { get; set; }
public string analytics_tracking_id { get; set; }
public string facebook_app_id { get; set; }
public string facebook_app_secret { get; set; }
public string google_app_id { get; set; }
public string google_app_secret { get; set; }
public bool noindex { get; set; }
#endregion
#region Constructors
public WebDomain()
{
// Set values for instance variables
this.id = 0;
this.website_name = "";
this.domain_name = "";
this.web_address = "";
this.front_end_language = 0;
this.back_end_language = 0;
this.analytics_tracking_id = "";
this.facebook_app_id = "";
this.facebook_app_secret = "";
this.google_app_id = "";
this.google_app_secret = "";
this.noindex = false;
} // End of the constructor
public WebDomain(SqlDataReader reader)
{
// Set values for instance variables
this.id = Convert.ToInt32(reader["id"]);
this.website_name = reader["website_name"].ToString();
this.domain_name = reader["domain_name"].ToString();
this.web_address = reader["web_address"].ToString();
this.front_end_language = Convert.ToInt32(reader["front_end_language"]);
this.back_end_language = Convert.ToInt32(reader["back_end_language"]);
this.analytics_tracking_id = reader["analytics_tracking_id"].ToString();
this.facebook_app_id = reader["facebook_app_id"].ToString();
this.facebook_app_secret = reader["facebook_app_secret"].ToString();
this.google_app_id = reader["google_app_id"].ToString();
this.google_app_secret = reader["google_app_secret"].ToString();
this.noindex = Convert.ToBoolean(reader["noindex"]);
} // End of the constructor
#endregion
} // End of the class
Arkivklass
Vårt arkivklass för webbdomäner innehåller alla metoder som vi behöver för att hantera webbdomäner på vår hemsida. Vi använder MS SQL som databas och distribuerad cache för att korta ned tiden det tar att hämta den aktuella domänen.
public class WebDomainRepository : IWebDomainRepository
{
#region Variables
private readonly IMsSqlDatabaseRepository database_repository;
private readonly IDistributedCache distributed_cache;
private readonly CacheOptions cache_options;
#endregion
#region Constructors
public WebDomainRepository(IMsSqlDatabaseRepository database_repository, IDistributedCache distributed_cache, IOptions<CacheOptions> cache_options)
{
this.database_repository = database_repository;
this.distributed_cache = distributed_cache;
this.cache_options = cache_options.Value;
} // End of the constructor
#endregion
#region Insert methods
public Int32 Add(WebDomain post)
{
// Create the int to return
Int32 idOfInsert = 0;
// Create the sql statement
string sql = "INSERT INTO dbo.web_domains (website_name, domain_name, web_address, front_end_language, back_end_language, "
+ "analytics_tracking_id, facebook_app_id, facebook_app_secret, google_app_id, google_app_secret, noindex) "
+ "VALUES (@website_name, @domain_name, @web_address, @front_end_language, @back_end_language, "
+ "@analytics_tracking_id, @facebook_app_id, @facebook_app_secret, @google_app_id, @google_app_secret, @noindex);SELECT CAST(SCOPE_IDENTITY() AS INT);";
// Create parameters
IDictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("@website_name", post.website_name);
parameters.Add("@domain_name", post.domain_name);
parameters.Add("@web_address", post.web_address);
parameters.Add("@front_end_language", post.front_end_language);
parameters.Add("@back_end_language", post.back_end_language);
parameters.Add("@analytics_tracking_id", post.analytics_tracking_id);
parameters.Add("@facebook_app_id", post.facebook_app_id);
parameters.Add("@facebook_app_secret", post.facebook_app_secret);
parameters.Add("@google_app_id", post.google_app_id);
parameters.Add("@google_app_secret", post.google_app_secret);
parameters.Add("@noindex", post.noindex);
// Insert the post
this.database_repository.Insert<Int32>(sql, parameters, out idOfInsert);
// Return the id of the inserted item
return idOfInsert;
} // End of the Add method
#endregion
#region Update methods
public void Update(WebDomain post)
{
// Create the sql statement
string sql = "UPDATE dbo.web_domains SET website_name = @website_name, domain_name = @domain_name, web_address = @web_address, "
+ "front_end_language = @front_end_language, back_end_language = @back_end_language, "
+ "analytics_tracking_id = @analytics_tracking_id, facebook_app_id = @facebook_app_id, facebook_app_secret = @facebook_app_secret, "
+ "google_app_id = @google_app_id, google_app_secret = @google_app_secret, noindex = @noindex WHERE id = @id;";
// Create parameters
IDictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("@website_name", post.website_name);
parameters.Add("@domain_name", post.domain_name);
parameters.Add("@web_address", post.web_address);
parameters.Add("@front_end_language", post.front_end_language);
parameters.Add("@back_end_language", post.back_end_language);
parameters.Add("@analytics_tracking_id", post.analytics_tracking_id);
parameters.Add("@facebook_app_id", post.facebook_app_id);
parameters.Add("@facebook_app_secret", post.facebook_app_secret);
parameters.Add("@google_app_id", post.google_app_id);
parameters.Add("@google_app_secret", post.google_app_secret);
parameters.Add("@noindex", post.noindex);
// Update the post
this.database_repository.Update(sql, parameters);
} // End of the Update method
#endregion
#region Count methods
public Int32 GetCountBySearch(string[] keywords)
{
// Create the sql statement
string sql = "SELECT COUNT(id) AS count FROM dbo.web_domains WHERE 1 = 1";
for (int i = 0; i < keywords.Length; i++)
{
sql += " AND (website_name LIKE @keyword_" + i.ToString() + " OR domain_name LIKE @keyword_" + i.ToString() + ")";
}
sql += ";";
// Create parameters
IDictionary<string, object> parameters = new Dictionary<string, object>();
for (int i = 0; i < keywords.Length; i++)
{
parameters.Add("@keyword_" + i.ToString(), "%" + keywords[i].ToString() + "%");
}
// Get the count
Int32 count = this.database_repository.GetCount<Int32>(sql, parameters);
// Return the count
return count;
} // End of the GetCountBySearch method
#endregion
#region Get methods
public WebDomain GetCurrentDomain(HttpContext context)
{
// Get the domain name
string domain_name = context.Request.Host.ToString();
// Replace www.
domain_name = domain_name.Replace("www.", "");
// Get the web domain post
WebDomain domain = GetFromCache(domain_name);
// Make sure that the domain not is null
if (domain == null)
{
domain = new WebDomain();
domain.id = 0;
domain.domain_name = "localhost";
domain.web_address = "https://localhost:80";
domain.front_end_language = 2;
domain.back_end_language = 2;
domain.analytics_tracking_id = "";
domain.facebook_app_id = "";
domain.facebook_app_secret = "";
domain.google_app_id = "";
domain.google_app_secret = "";
domain.noindex = true;
}
// Return the domain
return domain;
} // End of the GetCurrentDomain method
public KeyStringList GetDomainImageUrls(IHostingEnvironment environment, Int32 domain_id, bool showNoImageIcon)
{
// Create the list to return
KeyStringList imageUrls = new KeyStringList(5);
// Create paths
string directoryPath = "/domains/" + domain_id.ToString() + "/images/";
// Add images to the key string list
imageUrls.Add("background_image", directoryPath + "background_image.jpg");
imageUrls.Add("default_logotype", directoryPath + "default_logotype.png");
imageUrls.Add("mobile_logotype", directoryPath + "mobile_logotype.png");
imageUrls.Add("big_icon", directoryPath + "big_icon.png");
imageUrls.Add("small_icon", directoryPath + "small_icon.png");
if (showNoImageIcon == true)
{
// Create the no image path
string noImagePath = "/images/no_image_wide.jpg";
// Get all the keys in the dictionary
List<string> keys = imageUrls.dictionary.Keys.ToList<string>();
// Loop all the keys
for (int i = 0; i < keys.Count; i++)
{
// Get the url
string url = environment.WebRootPath + imageUrls.Get(keys[i]);
// Check if the file exists
if (System.IO.File.Exists(url) == false)
{
imageUrls.Update(keys[i], noImagePath);
}
}
}
// Return the list
return imageUrls;
} // End of the GetDomainImageUrls method
public WebDomain GetOneById(Int32 id)
{
// Create the sql statement
string sql = "SELECT * FROM dbo.web_domains WHERE id = @id;";
// Create parameters
IDictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("@id", id);
// Get a post
WebDomain post = this.database_repository.GetModel<WebDomain>(sql, parameters);
// Return the post
return post;
} // End of the GetOneById method
public WebDomain GetFromCache(string domain_name)
{
// Create the post to return
WebDomain post = null;
// Get the cached settings
string data = this.distributed_cache.GetString(domain_name);
if (data == null)
{
// Get the post
post = GetOneByDomainName(domain_name);
// Make sure that something was found in the database
if (post != null)
{
// Create cache options
DistributedCacheEntryOptions cacheEntryOptions = new DistributedCacheEntryOptions();
cacheEntryOptions.SetSlidingExpiration(TimeSpan.FromMinutes(this.cache_options.ExpirationInMinutes));
cacheEntryOptions.SetAbsoluteExpiration(TimeSpan.FromMinutes(this.cache_options.ExpirationInMinutes));
this.distributed_cache.SetString(domain_name, JsonConvert.SerializeObject(post), cacheEntryOptions);
}
}
else
{
post = JsonConvert.DeserializeObject<WebDomain>(data);
}
// Return the post
return post;
} // End of the GetFromCache method
public WebDomain GetOneByDomainName(string domain_name)
{
// Create the sql statement
string sql = "SELECT * FROM dbo.web_domains WHERE domain_name = @domain_name;";
// Create parameters
IDictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("@domain_name", domain_name);
// Get a post
WebDomain post = this.database_repository.GetModel<WebDomain>(sql, parameters);
// Return the post
return post;
} // End of the GetOneByDomainName method
public IList<WebDomain> GetAll(string sort_field, string sort_order)
{
// Make sure that sort variables are valid
sort_field = GetValidSortField(sort_field);
sort_order = GetValidSortOrder(sort_order);
// Create the sql statement
string sql = "SELECT * FROM dbo.web_domains ORDER BY " + sort_field + " " + sort_order + ";";
// Create parameters
IDictionary<string, object> parameters = new Dictionary<string, object>();
// Get the list of posts
IList<WebDomain> posts = this.database_repository.GetModelList<WebDomain>(sql, parameters, 10);
// Return the list of posts
return posts;
} // End of the GetAll method
public IList<WebDomain> GetBySearch(string[] keywords, Int32 page_size, Int32 page_number, string sort_field, string sort_order)
{
// Make sure that sort variables are valid
sort_field = GetValidSortField(sort_field);
sort_order = GetValidSortOrder(sort_order);
// Create the sql statement
string sql = "SELECT * FROM dbo.web_domains WHERE 1 = 1";
for (int i = 0; i < keywords.Length; i++)
{
sql += " AND (website_name LIKE @keyword_" + i.ToString() + " OR domain_name LIKE @keyword_" + i.ToString() + ")";
}
sql += " ORDER BY " + sort_field + " " + sort_order + " OFFSET @pageNumber ROWS FETCH NEXT @pageSize ROWS ONLY;";
// Create parameters
IDictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("@pageNumber", (page_number - 1) * page_size);
parameters.Add("@pageSize", page_size);
for (int i = 0; i < keywords.Length; i++)
{
parameters.Add("@keyword_" + i.ToString(), "%" + keywords[i].ToString() + "%");
}
// Get the list of posts
IList<WebDomain> posts = this.database_repository.GetModelList<WebDomain>(sql, parameters, page_size);
// Return the list of posts
return posts;
} // End of the GetBySearch method
#endregion
#region Delete methods
public Int32 DeleteOnId(Int32 id)
{
// Create the sql statement
string sql = "DELETE FROM dbo.web_domains WHERE id = @id;";
// Create parameters
IDictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("@id", id);
// Delete the post
Int32 errorNumber = this.database_repository.Delete(sql, parameters);
// Return error code
return errorNumber;
} // End of the DeleteOnId method
#endregion
#region Helper methods
public void RemoveFromCache()
{
// Get all domains
IList<WebDomain> posts = GetAll("domain_name", "ASC");
// Loop domains
for (int i = 0; i < posts.Count; i++)
{
// Get the data
string data = this.distributed_cache.GetString(posts[i].domain_name);
// Only remove the cache if it exists
if (data != null)
{
// Remove data from cache
this.distributed_cache.Remove(posts[i].domain_name);
}
}
} // End of the RemoveFromCache method
#endregion
#region Validation
public string GetValidSortField(string sort_field)
{
// Make sure that the sort field is valid
if (sort_field != "id" && sort_field != "website_name" && sort_field != "domain_name")
{
sort_field = "id";
}
// Return the string
return sort_field;
} // End of the GetValidSortField method
public string GetValidSortOrder(string sort_order)
{
// Make sure that the sort order is valid
if (sort_order != "ASC" && sort_order != "DESC")
{
sort_order = "ASC";
}
// Return the string
return sort_order;
} // End of the GetValidSortOrder method
#endregion
} // End of the class
Förfrågningar
Vi hämtar den aktuella domänen varje gång det görs en förfrågan på vår hemsida. Den aktuella domänen används för att hämta andra resurser, såsom statiska texter och bilder.
[HttpGet]
[Authorize(Roles = "Administrator,Editor,Translator")]
public IActionResult Index()
{
// Get the current domain
WebDomain current_domain = this.web_domain_repository.GetCurrentDomain(ControllerContext.HttpContext);
// Get translated texts
KeyStringList tt = this.static_text_repository.GetFromCache(current_domain.back_end_language, "id", "ASC");
// Set form data
ViewBag.CurrentDomain = current_domain;
ViewBag.TranslatedTexts = tt;
ViewBag.QueryParams = new QueryParams(ControllerContext.HttpContext.Request);
// Return the view
return View();
} // End of the index method