电商系统架构总结2(Redis)
二 Redis缓存
考虑到将来服务器的升级扩展,使用redis代替.net内置缓存是比较理想的选择。redis是非常成熟好用的缓存系统,安装配置非常简单,直接上官网下载安装包 安装启动就行了。
1 配置。redis安装后默认bind 接口是127.0.0.1,也就是本地回环地址。在开发环境下为了允许多个开发机器作为客户端访问,bind配置后面加上了本机局域网ip,如 bind 127.0.0.1 192.168.1.100 。
2 配置了redis读写分离。开发web api端的web.config件 增加配置项
<add name="RedisConnection_read" connectionString="192.168.0.100:6379" />
<add name="RedisConnection_write" connectionString="192.168.0.100:6379" />
redis 读写辅助类代码如下
- public class RedisCache: IRedisCache
- {
- private static string[] ReadWriteHosts = ConfigurationManager.ConnectionStrings["RedisConnection_read"].ConnectionString.Split(';');
- private static string[] ReadOnlyHosts = ConfigurationManager.ConnectionStrings["RedisConnection_write"].ConnectionString.Split(';');
- #region -- 连接信息 --
- public static PooledRedisClientManager prcm = CreateManager(ReadWriteHosts, ReadOnlyHosts);
- private static PooledRedisClientManager CreateManager(string[] readWriteHosts, string[] readOnlyHosts)
- {
- // 支持读写分离,均衡负载
- return new PooledRedisClientManager(readWriteHosts, readOnlyHosts, new RedisClientManagerConfig
- {
- MaxWritePoolSize = 5, // “写”链接池链接数
- MaxReadPoolSize = 5, // “读”链接池链接数
- AutoStart = true,
- });
- }
- #endregion
- #region -- Item --
- /// <summary>
- /// 设置单体
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="key"></param>
- /// <param name="t"></param>
- /// <param name="timeSpan"></param>
- /// <returns></returns>
- public bool Item_Set<T>(string key, T t)
- {
- try
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- return redis.Set<T>(key, t, new TimeSpan(1, 0, 0));
- }
- }
- catch (Exception ex)
- {
- throw ex;
- }
- }
- /// <summary>
- /// 设置单体
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="key"></param>
- /// <param name="t"></param>
- /// <param name="timeSpan"></param>
- /// <returns></returns>
- public bool Item_Set<T>(string key, T t, int timeout)
- {
- try
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- return redis.Set<T>(key, t, new TimeSpan(0, timeout, 0));
- }
- }
- catch (Exception ex)
- {
- throw ex;
- }
- }
- /// <summary>
- /// 获取单体
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="key"></param>
- /// <returns></returns>
- public T Item_Get<T>(string key) where T : class
- {
- using (IRedisClient redis = prcm.GetReadOnlyClient())
- {
- return redis.Get<T>(key);
- }
- }
- /// <summary>
- /// 设置缓存过期
- /// </summary>
- /// <param name="key"></param>
- /// <param name="datetime"></param>
- public bool Item_Remove(string key)
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- return redis.Remove(key);
- }
- }
- /// <summary>
- /// 设置缓存过期
- /// </summary>
- /// <param name="key"></param>
- public bool Item_SetExpire(string key, int timeout)
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- return redis.ExpireEntryIn(key, new TimeSpan(0, timeout, 0));
- }
- }
- #endregion
- #region -- List --
- public void List_Add<T>(string key, T t)
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- var redisTypedClient = redis.As<T>();
- redisTypedClient.AddItemToList(redisTypedClient.Lists[key], t);
- }
- }
- public void List_Set<T>(string key, List<T> list)
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- var redisTypedClient = redis.As<T>();
- redisTypedClient.Lists[key].RemoveAll();
- if (list != null)
- {
- list.ForEach(p =>
- {
- redisTypedClient.AddItemToList(redisTypedClient.Lists[key], p);
- });
- }
- }
- }
- public bool List_Remove<T>(string key, T t)
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- var redisTypedClient = redis.As<T>();
- return redisTypedClient.RemoveItemFromList(redisTypedClient.Lists[key], t) > 0;
- }
- }
- public void List_RemoveAll<T>(string key)
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- var redisTypedClient = redis.As<T>();
- redisTypedClient.Lists[key].RemoveAll();
- }
- }
- public void List_RemoveRange<T>(string key,List<T> list)
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- var redisTypedClient = redis.As<T>();
- if (list != null && list.Count > 0)
- {
- for(int i=0; i<list.Count;i++)
- {
- List_Remove<T>(key, list[i]);
- }
- }
- }
- }
- public long List_Count(string key)
- {
- using (IRedisClient redis = prcm.GetReadOnlyClient())
- {
- return redis.GetListCount(key);
- }
- }
- public List<T> List_GetRange<T>(string key, int start, int count)
- {
- using (IRedisClient redis = prcm.GetReadOnlyClient())
- {
- var c = redis.As<T>();
- return c.Lists[key].GetRange(start, start + count - 1);
- }
- }
- public List<T> List_GetList<T>(string key)
- {
- RedisClient client = new RedisClient("");
- using (IRedisClient redis = prcm.GetReadOnlyClient())
- {
- var c = redis.As<T>();
- return c.Lists[key].GetRange(0, c.Lists[key].Count);
- }
- }
- public List<T> List_GetList<T>(string key, int pageIndex, int pageSize)
- {
- int start = pageSize * (pageIndex - 1);
- return List_GetRange<T>(key, start, pageSize);
- }
- /// <summary>
- /// 设置缓存过期
- /// </summary>
- /// <param name="key"></param>
- /// <param name="datetime"></param>
- public void List_SetExpire(string key, DateTime datetime)
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- redis.ExpireEntryAt(key, datetime);
- }
- }
- #endregion
- #region -- Set --
- public void Set_Add<T>(string key, T t)
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- var redisTypedClient = redis.As<T>();
- redisTypedClient.Sets[key].Add(t);
- }
- }
- public bool Set_Contains<T>(string key, T t)
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- var redisTypedClient = redis.As<T>();
- return redisTypedClient.Sets[key].Contains(t);
- }
- }
- public bool Set_Remove<T>(string key, T t)
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- var redisTypedClient = redis.As<T>();
- return redisTypedClient.Sets[key].Remove(t);
- }
- }
- #endregion
- #region -- Hash --
- /// <summary>
- /// 判断某个数据是否已经被缓存
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="key"></param>
- /// <param name="dataKey"></param>
- /// <returns></returns>
- public bool Hash_Exist<T>(string key, string dataKey)
- {
- using (IRedisClient redis = prcm.GetReadOnlyClient())
- {
- return redis.HashContainsEntry(key, dataKey);
- }
- }
- /// <summary>
- /// 存储数据到hash表
- /// </summary>
- /// <typeparam name="T"></typeparam> Class1.cs
- /// <param name="key"></param>
- /// <param name="dataKey"></param>
- /// <returns></returns>
- public bool Hash_Set<T>(string key, string dataKey, T t)
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- string value = ServiceStack.Text.JsonSerializer.SerializeToString<T>(t);
- return redis.SetEntryInHash(key, dataKey, value);
- }
- }
- /// <summary>
- /// 移除hash中的某值
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="key"></param>
- /// <param name="dataKey"></param>
- /// <returns></returns>
- public bool Hash_Remove(string key, string dataKey)
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- return redis.RemoveEntryFromHash(key, dataKey);
- }
- }
- /// <summary>
- /// 移除整个hash
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="key"></param>
- /// <param name="dataKey"></param>
- /// <returns></returns>
- public bool Hash_Remove(string key)
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- return redis.Remove(key);
- }
- }
- /// <summary>
- /// 从hash表获取数据
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="key"></param>
- /// <param name="dataKey"></param>
- /// <returns></returns>
- public T Hash_Get<T>(string key, string dataKey)
- {
- using (IRedisClient redis = prcm.GetReadOnlyClient())
- {
- string value = redis.GetValueFromHash(key, dataKey);
- return ServiceStack.Text.JsonSerializer.DeserializeFromString<T>(value);
- }
- }
- /// <summary>
- /// 获取整个hash的数据
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="key"></param>
- /// <returns></returns>
- public List<T> Hash_GetAll<T>(string key)
- {
- using (IRedisClient redis = prcm.GetReadOnlyClient())
- {
- var list = redis.GetHashValues(key);
- if (list != null && list.Count > 0)
- {
- List<T> result = new List<T>();
- foreach (var item in list)
- {
- var value = ServiceStack.Text.JsonSerializer.DeserializeFromString<T>(item);
- result.Add(value);
- }
- return result;
- }
- return null;
- }
- }
- /// <summary>
- /// 设置缓存过期
- /// </summary>
- /// <param name="key"></param>
- /// <param name="datetime"></param>
- public void Hash_SetExpire(string key, DateTime datetime)
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- redis.ExpireEntryAt(key, datetime);
- }
- }
- /// <summary>
- /// 获取Hash集合数量
- /// </summary>
- /// <param name="key">Hashid</param>
- public long Hash_GetCount(string key)
- {
- using (IRedisClient redis = prcm.GetReadOnlyClient())
- {
- return redis.GetHashCount(key);
- }
- }
- #endregion
- #region -- SortedSet --
- /// <summary>
- /// 添加数据到 SortedSet
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="key"></param>
- /// <param name="t"></param>
- /// <param name="score"></param>
- public bool SortedSet_Add<T>(string key, T t, double score)
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- string value = ServiceStack.Text.JsonSerializer.SerializeToString<T>(t);
- return redis.AddItemToSortedSet(key, value, score);
- }
- }
- /// <summary>
- /// 移除数据从SortedSet
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="key"></param>
- /// <param name="t"></param>
- /// <returns></returns>
- public bool SortedSet_Remove<T>(string key, T t)
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- string value = ServiceStack.Text.JsonSerializer.SerializeToString<T>(t);
- return redis.RemoveItemFromSortedSet(key, value);
- }
- }
- /// <summary>
- /// 修剪SortedSet
- /// </summary>
- /// <param name="key"></param>
- /// <param name="size">保留的条数</param>
- /// <returns></returns>
- public long SortedSet_Trim(string key, int size)
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- return redis.RemoveRangeFromSortedSet(key, size, 9999999);
- }
- }
- /// <summary>
- /// 获取SortedSet的长度
- /// </summary>
- /// <param name="key"></param>
- /// <returns></returns>
- public long SortedSet_Count(string key)
- {
- using (IRedisClient redis = prcm.GetReadOnlyClient())
- {
- return redis.GetSortedSetCount(key);
- }
- }
- /// <summary>
- /// 获取SortedSet的分页数据
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="key"></param>
- /// <param name="pageIndex"></param>
- /// <param name="pageSize"></param>
- /// <returns></returns>
- public List<T> SortedSet_GetList<T>(string key, int pageIndex, int pageSize)
- {
- using (IRedisClient redis = prcm.GetReadOnlyClient())
- {
- var list = redis.GetRangeFromSortedSet(key, (pageIndex - 1) * pageSize, pageIndex * pageSize - 1);
- if (list != null && list.Count > 0)
- {
- List<T> result = new List<T>();
- foreach (var item in list)
- {
- var data = ServiceStack.Text.JsonSerializer.DeserializeFromString<T>(item);
- result.Add(data);
- }
- return result;
- }
- }
- return null;
- }
- /// <summary>
- /// 获取SortedSet的全部数据
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="key"></param>
- /// <param name="pageIndex"></param>
- /// <param name="pageSize"></param>
- /// <returns></returns>
- public List<T> SortedSet_GetListALL<T>(string key)
- {
- using (IRedisClient redis = prcm.GetReadOnlyClient())
- {
- var list = redis.GetRangeFromSortedSet(key, 0, 9999999);
- if (list != null && list.Count > 0)
- {
- List<T> result = new List<T>();
- foreach (var item in list)
- {
- var data = ServiceStack.Text.JsonSerializer.DeserializeFromString<T>(item);
- result.Add(data);
- }
- return result;
- }
- }
- return null;
- }
- /// <summary>
- /// 设置缓存过期
- /// </summary>
- /// <param name="key"></param>
- /// <param name="datetime"></param>
- public void SortedSet_SetExpire(string key, DateTime datetime)
- {
- using (IRedisClient redis = prcm.GetClient())
- {
- redis.ExpireEntryAt(key, datetime);
- }
- }
- #endregion
- }
3 用 redis实现 分布式 跨应用session共享,同样,web api 的webconfig文件里session配置为
- <system.web>
- <sessionState mode="Custom" customProvider="RedisSessionStateStore">
- <providers>
- <add name="RedisSessionStateStore" type="MyProject.RedisSessionStateStore" />
- </providers>
- </sessionState>
- ...
- <system.web>
- RedisSessionStateStore实现代码如下:
- public class RedisSessionStateStore : SessionStateStoreProviderBase
- {
- IRedisCache redis;
- public RedisSessionStateStore()
- {
- redis = IDAL.DALContainer.Resolve<IRedisCache>();
- }
- public override SessionStateStoreData CreateNewStoreData(HttpContext context, int timeout)
- {
- return CreateLegitStoreData(context, null, null, timeout);
- }
- internal static SessionStateStoreData CreateLegitStoreData(HttpContext context, ISessionStateItemCollection sessionItems, HttpStaticObjectsCollection staticObjects, int timeout)
- {
- if (sessionItems == null)
- sessionItems = new SessionStateItemCollection();
- if (staticObjects == null && context != null)
- staticObjects = SessionStateUtility.GetSessionStaticObjects(context);
- return new SessionStateStoreData(sessionItems, staticObjects, timeout);
- }
- public override void CreateUninitializedItem(HttpContext context, string id, int timeout)
- {
- RedisSessionState state = new RedisSessionState(null, null, timeout);
- redis.Item_Set<string>(id, state.ToJson(), timeout);
- }
- private SessionStateStoreData DoGet(HttpContext context, string id, bool exclusive, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actionFlags)
- {
- locked = false;
- lockId = null;
- lockAge = TimeSpan.Zero;
- actionFlags = SessionStateActions.None;
- RedisSessionState state = RedisSessionState.FromJson(redis.Item_Get<string>(id));
- if (state == null)
- {
- return null;
- }
- redis.Item_SetExpire(id, state._timeout);
- return CreateLegitStoreData(context, state._sessionItems, state._staticObjects, state._timeout);
- }
- public override SessionStateStoreData GetItem(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actionFlags)
- {
- return this.DoGet(context, id, false, out locked, out lockAge, out lockId, out actionFlags);
- }
- public override SessionStateStoreData GetItemExclusive(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actionFlags)
- {
- return this.DoGet(context, id, true, out locked, out lockAge, out lockId, out actionFlags);
- }
- public override void SetAndReleaseItemExclusive(HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem)
- {
- ISessionStateItemCollection sessionItems = null;
- HttpStaticObjectsCollection staticObjects = null;
- if (item.Items.Count > 0)
- sessionItems = item.Items;
- if (!item.StaticObjects.NeverAccessed)
- staticObjects = item.StaticObjects;
- RedisSessionState state2 = new RedisSessionState(sessionItems, staticObjects, item.Timeout);
- redis.Item_Set<string>(id, state2.ToJson(), item.Timeout);
- }
- #region "未实现方法"
- public override void Dispose()
- {
- }
- public override void EndRequest(HttpContext context)
- {
- }
- public override void InitializeRequest(HttpContext context)
- {
- }
- public override void ReleaseItemExclusive(HttpContext context, string id, object lockId)
- {
- }
- public override void RemoveItem(HttpContext context, string id, object lockId, SessionStateStoreData item)
- {
- redis.Item_Remove(id);
- }
- public override void ResetItemTimeout(HttpContext context, string id)
- {
- }
- public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback)
- {
- return true;
- }
- #endregion
- }
- internal sealed class SessionStateItem
- {
- public Dictionary<string, SaveValue> Dict;
- public int Timeout;
- }
- internal sealed class SaveValue
- {
- public object Value { get; set; }
- public Type Type { get; set; }
- }
- internal sealed class RedisSessionState
- {
- internal ISessionStateItemCollection _sessionItems;
- internal HttpStaticObjectsCollection _staticObjects;
- internal int _timeout;
- internal RedisSessionState(ISessionStateItemCollection sessionItems, HttpStaticObjectsCollection staticObjects, int timeout)
- {
- this.Copy(sessionItems, staticObjects, timeout);
- }
- internal void Copy(ISessionStateItemCollection sessionItems, HttpStaticObjectsCollection staticObjects, int timeout)
- {
- this._sessionItems = sessionItems;
- this._staticObjects = staticObjects;
- this._timeout = timeout;
- }
- public string ToJson()
- {
- // 这里忽略_staticObjects这个成员。
- if (_sessionItems == null || _sessionItems.Count == 0)
- {
- return null;
- }
- Dictionary<string, SaveValue> dict = new Dictionary<string, SaveValue>(_sessionItems.Count);
- NameObjectCollectionBase.KeysCollection keys = _sessionItems.Keys;
- string key;
- object objectValue = string.Empty;
- Type type = null;
- //2016-09-04解决存入值没有类型导致读取值是jobject问题
- for (int i = 0; i < keys.Count; i++)
- {
- key = keys[i];
- objectValue = _sessionItems[key];
- if (objectValue != null)
- {
- type = objectValue.GetType();
- }
- else
- {
- type = typeof(object);
- }
- dict.Add(key, new SaveValue { Value = objectValue, Type = type });
- }
- SessionStateItem item = new SessionStateItem { Dict = dict, Timeout = this._timeout };
- return JsonConvert.SerializeObject(item);
- }
- public static RedisSessionState FromJson(string json)
- {
- if (string.IsNullOrEmpty(json))
- {
- return null;
- }
- try
- {
- SessionStateItem item = JsonConvert.DeserializeObject<SessionStateItem>(json);
- SessionStateItemCollection collections = new SessionStateItemCollection();
- SaveValue objectValue = null;
- //2016-09-04解决读取出来的值 没有类型的问题
- JsonSerializer serializer = new JsonSerializer();
- StringReader sr = null;
- JsonTextReader tReader = null;
- foreach (KeyValuePair<string, SaveValue> kvp in item.Dict)
- {
- objectValue = kvp.Value as SaveValue;
- if (objectValue.Value == null)
- {
- collections[kvp.Key] = null;
- }
- else
- {
- if (!IsValueType(objectValue.Type))
- {
- sr = new StringReader(objectValue.Value.ToString());
- tReader = new JsonTextReader(sr);
- collections[kvp.Key] = serializer.Deserialize(tReader, objectValue.Type);
- }
- else
- {
- collections[kvp.Key] = objectValue.Value;
- }
- }
- }
- return new RedisSessionState(collections, null, item.Timeout);
- }
- catch
- {
- return null;
- }
- }
- /// <summary>
- /// 判断是否为值类型
- /// </summary>
- /// <param name="type">Type</param>
- /// <returns></returns>
- public static bool IsValueType(Type type)
- {
- if (type.IsValueType)
- {
- return true;
- }
- //基础数据类型
- if (type == typeof(string) || type == typeof(char)
- || type == typeof(ushort) || type == typeof(short) || type == typeof(uint) || type == typeof(int)
- || type == typeof(ulong) || type == typeof(long) || type == typeof(double) || type == typeof(decimal)
- || type == typeof(bool)
- || type == typeof(byte))
- {
- return true;
- }
- //可为null的基础数据类型
- if (type.IsGenericType && !type.IsGenericTypeDefinition)
- {
- Type genericType = type.GetGenericTypeDefinition();
- if (Object.ReferenceEquals(genericType, typeof(Nullable<>)))
- {
- var actualType = type.GetGenericArguments()[0];
- return IsValueType(actualType);
- }
- }
- return false;
- }
- }
电商系统架构总结2(Redis)的更多相关文章
- 电商系统架构总结1(EF)
最近主导了一个电商系统的设计开发过程,包括前期分析设计,框架搭建,功能模块的具体开发(主要负责在线支付部分),成功上线后的部署维护,运维策略等等全过程. 虽然这个系统不是什么超大型的电商系统 数亿计的 ...
- 电商系统架构总结4(webapi 版本控制)
为了 顺利迭代升级,web api 在维护过程是不断升级的,但用户是不能强迫他们每次都跟随你去升级,这样会让用户不胜其烦.为了保证不同版本的客户端能同时兼容,在web api接口上加入版本控制就很有必 ...
- 电商系统架构总结3(webapi授权机制)
三 Web API 授权方式 web api的客户端,包括 android,ios,h5,自然对访问权限要加上授权机制.对于h5,要求把h5站点和web api部署在同一个域名下,然后对web api ...
- SpringBoot+Security+MyBatis+ES+MQ+Redis+Docker+Vue的电商系统
今天鹏哥给大家推荐的项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现. 前台商城系统包含首页门户.商品推荐.商品搜索.商品展示.购物车.订单流程.会员中 ...
- 电商系统的演变可以看出架构演变 Dubbo入门 远程过程调用 需要解决的问题
Dubbo入门---搭建一个最简单的Demo框架 - CSDN博客 https://blog.csdn.net/noaman_wgs/article/details/70214612 Dubbo背景和 ...
- 属性 每秒10万吞吐 并发 架构 设计 58最核心的帖子中心服务IMC 类目服务 入口层是Java研发的,聚合层与检索层都是C语言研发的 电商系统里的SKU扩展服务
小结: 1. 海量异构数据的存储问题 如何将不同品类,异构的数据统一存储起来呢? (1)全品类通用属性统一存储: (2)单品类特有属性,品类类型与通用属性json来进行存储: 2. 入口层是Java研 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统
本来想在Dpar 1.0GA时发布这篇文章,由于其他事情耽搁了放到现在.时下微服务和云原生技术如何如荼,微软也不甘示弱的和阿里一起适时推出了Dapr(https://dapr.io/),园子里关于da ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(十)——一步一步教你如何撸Dapr之绑定
如果说Actor是dapr有状态服务的内部体现的话,那绑定应该是dapr对serverless这部分的体现了.我们可以通过绑定极大的扩展应用的能力,甚至未来会成为serverless的基础.最开始接触 ...
- 集DDD,TDD,SOLID,MVVM,DI,EF,Angularjs等于一身的.NET(C#)开源可扩展电商系统–Virto Commerce
今天一大早来看到园友分享的福利<分享一个前后端分离方案源码-前端angularjs+requirejs+dhtmlx 后端asp.net webapi>,我也来分享一个吧.以下内容由笔者写 ...
随机推荐
- Python基础_私有变量访问限制
Python内置了一些特殊变量,以前后上下划线标注,同时我们自己要想定义一些变量,不想让外部访问,又该怎么做呢?更多内容请参考:Python学习指南 访问限制 在class内部,可以有属性和方法,而外 ...
- 读懂 PetaLinux:让 Linux 在 Zynq 上轻松起“跑”(转)
对于Zynq这样一个“ARM+可编程逻辑”异构处理系统我们已经不陌生,其创新性大家也有目共睹.不过想要让更多的应用享受到这一“创新”带来的红利,让其真正“落地”则需要大量系统性的工作,去营造一个完善的 ...
- win7重装系统笔记
制作U盘启动盘:链接 原文链接:链接 开机进入bios界面(华硕:F2) 按方向左右键进入:Boot选项,将“Lunch CSM”设置为“Enabled” 方向键选择“Security”,将“Secu ...
- Linux vi文本编辑器
vi文本编辑器 1.最基本用法 vi somefile.4 1/ 首先会进入“一般模式”,此模式只接受各种命令快捷键,不能编辑文件内容 2/ 按i键,就会从一般模式进入编辑模式,此模式下,敲入的都是 ...
- [视频播放] M3U8文件格式说明
M3U文件中可以包含多个tag,每个tag的功能和属性如下: #EXTM3U 每个M3U文件第一行必须是这个tag,请标示作用 #EXT-X-MEDIA-SEQUENCE:140651513 每一个m ...
- ALGO-152_蓝桥杯_算法训练_8-2求完数
记: 掌握完数的概念 AC代码: #include <stdio.h> int main(void) { int i,j,sum; ; i <= ; i ++) { sum = ; ...
- ghost之后仍然中病毒----与病毒的斗争
ghost之后仍然中病毒----与病毒的斗争我的电脑系统是XP,从来都没有安装任何杀毒软件,所有的软件都是安装在C盘的,感觉系统卡顿就用Windows一键还原(基于DOS下的ghost)还原一下,一直 ...
- 2、以自定义struct或struct指针作为map的Key
若干问题: struct Node { int k, b; friend bool operator <(Node a, Node b) { return a.k < b.k; } }no ...
- 函数,lambda函数,递归函数,内置函数(map,filter),装饰器
1. 集合 主要作用: 去重 关系测试, 交集\差集\并集\反向(对称)差集 2. 元组 只读列表,只有count, index 2 个方法 作用:如果一些数据不想被人修改, 可以存成元组,比如身份证 ...
- opengl 入门浅学(一)
因为要做图形学的实验,又是要以OPENGL为基础,所以就稍微在网上查了一些资料. 我是带着目的去学习的,所以就没有打基础之类的学很深,浅尝. 今天试着搭简单框架,画出一个图形.大神请出门左转. #in ...