Http协议,底层的东西仍是不是特别熟悉,感受要通过沉淀以后才能理解这些东西吧
1.Asp.net生命周期
Asp.net生命周期:
从发起请求开始,到IIS进行处理的所有过程,而后再到获取结果
当请求一个*.aspx文件的时候,这个请求会被inetinfo.exe进程截获,它判断文件的后缀(aspx)以后,将这个请求转交给ASPNET_ISAPI.dll,ASPNET_ISAPI.dll会经过http管道(Http PipeLine)将请求发送给ASPNET_WP.exe进程,在ASPNET_WP.exe进程中经过HttpRuntime来处理这个请求,处理完毕将结果返回客户端。 inetinfo.exe进程:是www服务的进程,IIS服务和ASPNET_ISAPI.DLL都寄存在此进程中。 ASPNET_ISAPI.DLL:是处理.aspx文件的win32组件。其实IIS服务器是只能识别.html文件的,当IIS服务器发现被请求的文件是.aspx文件时,IIS服务器将其交给aspnet_isapi.dll来处理。 aspnet_wp.exe进程:ASP.NET框架进程,提供.net运行的托管环境,.net的CLR(公共语言运行时)就是寄存在此进程中。
ASP.NET Framework处理一个Http Request的流程: HttpRequest-->inetinfo.exe-->ASPNET_ISAPI.dll-->ASPNET_WP.exe-->HttpRuntime-->HttpApplication Factory-->HttpApplication-->HttpModule-->HttpHandler Factory-->HttpHandler-->HttpHandler.ProcessRequest()
ASP.NET请求处理过程是基于管道模型的,这个管道模型是由多个HttpModule和HttpHandler组成,ASP.NET把http请求依次传递给管道中各个HttpModule,最终被HttpHandler处理,处理完成后,再次通过管道中的HTTP模块,把结果返回给客户端。咱们能够在每一个HttpModule中均可以干预请求的处理过程。
2.Htpp协议的生命周期
这个感受要后续继续加深理解以后再进行补充吧,目前就拿别人的思路来解答这个过程
1.输入url,浏览器DNS解析域名,获取ip
2.三次握手,创建tcp连接
3.向服务端发送http请求
4.服务端处理请求并响应
5.浏览器渲染HTML
6在渲染的过程当中继续加载css,js,图片,音频,视频文件
7 呈现给用户
托管代码与非托管代码的区别
实际上是知道这个东西,可是不知道专业术语竟然叫这个,我觉得是Azure云托管,好吧,开个玩笑
不止C#,java也是托管代码啊,重点,重点,重点!!!
1.简单的说,就是代码被编译成MSIL后在.net的Framework下运行,同操做系统底层的交互都交给framework去作。所谓非托管代码就是脱离了Framework的管制,
直接同底层API打交道,本身管理本身的内存和安全机制等东西。而托管代码就无论这些,全都由Framework去完成
2.“程序”通常都是在对操做系统进行直接或者间接的操做
“托管程序”是须要经过访问公共语言运行时(cls)才能访问操做系统的程序
而“非托管程序”不用经过访问公共语言运行时(cls)能够直接访问操做系统的程序
3.vb.net,C#等写的程序是托管程序,VC++能够写托管程序,若是用到了内存管理,则只能编译为非托管程序这些东西MSDN都有描述
经过IEnumerable接口遍历数据
使用IEnumerable接口遍历数据,这在项目中会常常的用到,这个类型呢主要是一个枚举器。
1.首先须要让该类型实现一个名字叫IEnumerable的接口,实现该接口的主要目的是为了让当前类型中增长一个名字叫GetEnumerator()的方法。
public class Person : IEnumerable { private string[] Friends = new string[] { "张三", "李四", "王五", "赵六" }; public string Name { get; set; } public int Age { get; set; } public string Email { get; set; } #region IEnumerable 成员 //这个方法的做用就是返回一个“枚举器” public IEnumerator GetEnumerator() { return new PersonEnumerator(this.Friends); } #endregion }
2.但愿一个类型被枚举遍历,就是要实现一个枚举器方法
public class PersonEnumerator : IEnumerator { public PersonEnumerator(string[] fs) { _friends = fs; } private string[] _friends; //通常下标都是一开始指向了第一条的前一条。第一条是0 private int index = -1; #region IEnumerator 成员 public object Current { get { if (index >= 0 && index < _friends.Length) //下标有范围 { return _friends[index]; } else { throw new IndexOutOfRangeException(); } } } public bool MoveNext() { if (index + 1 < _friends.Length) //下标有范围 { index++; return true; } return false; } public void Reset() { index = -1; } #endregion }
3.而后进行遍历,这里呢能够调用本身封装的MoveNext方法去找数组元素
Person p = new Person(); IEnumerator etor = p.GetEnumerator(); while (etor.MoveNext()) { Console.WriteLine(etor.Current.ToString()); }
也能够直接使用foreach,并且主要是由于是枚举元素,相似与数组,list等等之类的,均可以使用Lambda表达式来进行数据的处理
Person p = new Person(); foreach (string item in p) { Console.WriteLine(item); } Console.WriteLine("ok");
4.输出的结果以下:
依赖注入与控制反转
反正这个概念我通常都是不去记得,首先看一下什么是依赖:
有一个类是Animal,而后我定义了一个BlackCat类,类里面有一个BlackCat方法,那么这里的BlackCat就依赖Animal
public class BlackCat { public BlackCat(Animal Cat) { Cry(); } }
BlackCat类实例化的时候须要一个Animal的对象做为构造函数的参数,那么BlackCat就依赖Animal,这就叫依赖。
固然,不用构造函数的方式,在BlackCat类内部去new一个Animal,也是依赖;固然注入的话,就像是你写了一个类,而后
经过IOC框架,把这个类注入到其余类中,这就是注入
控制反转的意思就好理解了,就好比我定义了一个类,类里面有一个方法,而后我如今要把这个方法的控制权交给别人来使用,这就是控制反转。
在编写代码的时候,咱们须要把一些接口编写成通用的道理就在这里了,便于作到代码复用
下面即以猫的例子来进行解说控制反转
1.先定义一个动物类
using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IOC { class Animal { public void Cry() { Console.Write("动物喊叫"); } } }
2.定义一个猫的类
using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IOC { class Cat:Animal { public void Cry() { Console.WriteLine("动物喊叫"); } } }
3.我用实例化一个动物类,而后查看结果
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IOC { class Program { static void Main(string[] args) { Animal A = new Cat(); A.Cry(); Console.ReadLine(); } } }
4.能够看到我用子类能够替换掉父类,也能够用父类替换掉子类,其实并无太大的影响
Animal A = new Cat();
能够看见输出结果以下
C#多线程——优先级
在个人公司这里,由于要跟不少特殊的设备打交道,因此会用到多线程的东西,那么咱们在进行多线程处理的时候,怎么去设置优先级
我这里用听歌和下载小说作了个例子,咱们用电脑的时候确定是能够边听歌边下载小说的,那么这就须要并行,有个问题就是我想优先听
歌,下载小说对我来讲不是那么急的话我就能够对两个事情进行优先级的管控。
线程里有个属性Priority能够用来设置优先级,我设置线程1的优先级高于线程2的优先级,那么线程1就会比线程2多运行一段时间,这个是人眼观察不出来的
运行速度,CPU运行速度可不是能用人眼查看的
bool b = true; int i=0, j=0; string Song = ""; string Download = ""; Thread Thread1=new Thread(() => { while (b) { Song="一百万个可能"; i++; } }) { Name = "Thread1", Priority = ThreadPriority.Highest }; Thread Thread2=new Thread(() => { while (b) { Download = "小说三体"; j++; } }) { Name = "Thread2", Priority = ThreadPriority.Lowest }; Thread1.Start(); Thread2.Start(); Thread.Sleep(1000); b = false; Console.WriteLine("Song: {0}, Download: {1}", Song, Download); Console.WriteLine("歌曲的优先级:{0}",i); Console.WriteLine("下载的优先级:{0}",j); Console.ReadLine();
这里咱们看一下执行结果
从结果中能够看到,优先级高的线程获得运行的次数比优先级低的线程多,但即便是最低优先级的线程都有很大的机会来执行。
AutoFac容器初步
转载请注明出处,AutoFac:最流行的依赖注入和IOC框架,轻量且高性能,对项目代码几乎无任何侵入性。
那么咱们怎么来使用这样一个框架呢
一、在引用项右击,选择Nuget管理,这里咱们要导入两个包
一个是AutoFac包,另一个就是Autofac ASP.NET MVC5 Intergration
在webapi里面使用的话咱们须要添加一个Autofac ASP.NET Web API2.2 Intergration 才能够。
2.Global.asax.cs属性注入,配置IOC容器,我这里配置的是通用的以I开头的Repository(仓库类)
#region autofac IOC容器配置 var builder = new ContainerBuilder(); //注册全部的controller builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired(); //注册全部模块module builder.RegisterAssemblyModules(Assembly.GetExecutingAssembly()); var assemblys = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray(); //注册全部继承IDependency接口的类 builder.RegisterAssemblyTypes(assemblys) .Where(type => typeof(IDependency).IsAssignableFrom(type) && !type.IsAbstract); //注册服务,全部IxxxxRepository=>xxxxRepository builder.RegisterAssemblyTypes(assemblys).Where(t => t.Name.EndsWith("Repository") && !t.Name.StartsWith("I")).AsImplementedInterfaces(); var container = builder.Build(); BaseInfo._container = container; DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); #endregion
3.新建实体基类以及实体类,也就是建立数据模型
base类:
public class BaseEntity { [NotMapped] [PropertyModelBinder("start")] public int pageIndex { get; set; } [NotMapped] [PropertyModelBinder("length")] public int pageSize { get; set; } [NotMapped] public string draw { get; set; } [NotMapped] public List<Orderby> order { get; set; } [NotMapped] public List<Datacolumn> columns { get; set; } } public class Orderby { public string column { get; set; } public string dir { get; set; } } public class Datacolumn { public string data { get; set; } public string name { get; set; } public bool searchable { get; set; } public bool orderable { get; set; } }
实体类:
public class User : BaseEntity { public User() { RoleList = new List<Role>(); MessageList = new List<UserMappingMessage>(); } public int UserID { get; set; } public string UserName { get; set; } public string UserPassword {get;set;} public string UserReallyname {get;set;} public string HeadPortrait { get; set; } public string MobilePhone { get; set; } public string Email { get; set; } public int DepartmentID {get;set;} public bool IsEnable {get;set;} public DateTime CreateTime {get;set;} public DateTime? UpdateTime {get;set;} public string Remark { get; set; } public ICollection<Role> RoleList { get; set; } //接收消息列表 public ICollection<UserMappingMessage> MessageList { get; set; } public Dictionary Department { get; set; } //发送消息列表 public List<Message> Messages { get; set; } }
4.建立仓储接口,由于我在配置Global属性时,已经说明了我要注入全部以 “I” 开头的接口,那么我就把这个用户的接口给定义为IUserRepository
固然,不一样的实体类所须要的仓储接口也不同,这里根据本身的实际需求去写须要的方法类,接口嘛,就不要在这里具体实现你的方法了
public interface IUserRepository { Tuple<int,List<User>> GetList(User model); List<User> GetUserInfos(); User GetSingle(User model); User GetbyID(int userID); void AddUser(User model); void ModifyUser(User model); void DeleteUser(User model); void SetUserInfoRole(int userID, List<int> roleIDList); List<AutoUserDo> GetUserInfobyName(string value); void ResetUserPWDbyID(int id); }
5.咱们定义一个实现接口的类,而后把接口的方法给实现,这里面就是对数据实体进行操做了
public class UserRepository : IUserRepository { public Tuple<int, List<User>> GetList(User model) { using (UnitOfWork dal=BaseInfo._container.Resolve<UnitOfWork>()) { var SysUserRepository = dal.GetRepository<User>(); var conditions = ExpandHelper.True<User>(); if (!string.IsNullOrEmpty(model.UserName)) conditions = conditions.And(a => a.UserName.Contains(model.UserName)); if (!string.IsNullOrEmpty(model.UserReallyname)) conditions = conditions.And(a => a.UserReallyname.Contains(model.UserReallyname)); if (model.DepartmentID > 0) conditions = conditions.And(a => a.DepartmentID == model.DepartmentID); var templist = SysUserRepository.Get(filter: conditions, includeProperties: "RoleList"); var count = templist.Count(); if (model.order != null&&model.order.Count()>0) { foreach (var item in model.order) { var column = model.columns.ElementAt(int.Parse(item.column)); templist = templist.OrderSort(column.data, item.dir); } } var result = templist.PageBy(model.pageIndex, model.pageSize).ToList(); return new Tuple<int, List<User>>(count, result); } } public User GetSingle(User model) { using(UnitOfWork dal=BaseInfo._container.Resolve<UnitOfWork>()){ var conditions = ExpandHelper.True<User>(); if (!string.IsNullOrEmpty(model.UserName)) conditions = conditions.And( a => a.UserName == model.UserName || a.MobilePhone == model.UserName); if (!string.IsNullOrEmpty(model.MobilePhone)) conditions = conditions.And(a => a.MobilePhone == model.MobilePhone); var result = dal.GetRepository<User>().Get(conditions).FirstOrDefault(); return result; } } public User GetbyID(int userID) { using (UnitOfWork dal = BaseInfo._container.Resolve<UnitOfWork>()) { // var result = dal.GetRepository<User>().Get(filter: a => a.UserID == userID, includeProperties: "RoleList.MenuList,RoleList.rbList").AsNoTracking().FirstOrDefault(); var result = dal.GetRepository<User>().Get(filter: a => a.UserID == userID,includeProperties: "RoleList").FirstOrDefault(); foreach (var item in result.RoleList) { var role=dal.GetRepository<Role>().Get(a=>a.RoleID==item.RoleID,includeProperties:"MenuList,rbList").FirstOrDefault(); item.MenuList = role.MenuList; item.rbList = role.rbList; } return result; } } public void AddUser(User model) { using (UnitOfWork dal = BaseInfo._container.Resolve<UnitOfWork>()) { dal.GetRepository<User>().Insert(model); dal.Save(); } } public void ModifyUser(User model) { using (UnitOfWork dal = BaseInfo._container.Resolve<UnitOfWork>()) { dal.GetRepository<User>().UpdateSup(model, new List<string>() { "IsEnable", "CreateTime" }, false); dal.Save(); } } public void DeleteUser(User model) { using (UnitOfWork dal = BaseInfo._container.Resolve<UnitOfWork>()) { var sysUserRepository= dal.GetRepository<User>(); var Usermodel = sysUserRepository.GetByID(model.UserID); Usermodel.IsEnable=Usermodel.IsEnable?false:true; sysUserRepository.UpdateSup(Usermodel, new List<string>() { "IsEnable" }); dal.Save(); } } /// <summary> /// 添加用户角色信息,先删除原有数据,在添加到数据库 /// </summary> /// <param name="userID"></param> /// <param name="roleIDList"></param> /// <returns></returns> public void SetUserInfoRole(int userID, List<int> roleIDList) { using (UnitOfWork dal = BaseInfo._container.Resolve<UnitOfWork>()) { var sysUserRepository = dal.GetRepository<User>(); var roleRepository = dal.GetRepository<Role>(); var UserModel = GetbyID(userID); var roleList = UserModel.RoleList.ToList(); roleList.ForEach(m => { var userModel = sysUserRepository.Get(filter: a => a.UserID == userID, includeProperties: "RoleList").FirstOrDefault(); var roleModel = roleRepository.GetByID(m.RoleID); userModel.RoleList.Remove(roleModel); }); roleIDList.ForEach(m => { var userModel = sysUserRepository.GetByID(userID); var roleModel = roleRepository.GetByID(m); userModel.RoleList.Add(roleModel); }); dal.Save(); } } public List<AutoUserDo> GetUserInfobyName(string value) { Mapper.Initialize(a => { a.CreateMap<User, AutoUserDo>() .ForMember(au => au.id, op => { op.MapFrom(user => user.UserID); }) .ForMember(au => au.text, op => { op.MapFrom(user => user.UserReallyname); }) .ForMember(au => au.department, op => { op.MapFrom(user => user.Department.DicValue); }); a.CreateMap<Role, roleinfo>(); }); using (var dal = BaseInfo._container.Resolve<UnitOfWork>()) { return dal.GetRepository<User>() .Get(a => a.UserReallyname.Contains(value) || a.MobilePhone == value, includeProperties: "Department,Role").ProjectToQueryable<AutoUserDo>().ToList(); } } public void ResetUserPWDbyID(int id) { using (var dal = BaseInfo._container.Resolve<UnitOfWork>()) { var repository = dal.GetRepository<User>(); var usermodel = new User() { UserID = id, UserPassword = "123456" }; repository.UpdateSup(usermodel, new List<string>() { "UserPassword" }); dal.Save(); } } public List<User> GetUserInfos() { using (var dal = BaseInfo._container.Resolve<UnitOfWork>()) { return dal.GetRepository<User>().Get().ToList(); } } }
6.而后咱们就能够在MVC的控制器里面去调用这些方法来实现咱们所想要的功能了,我这里只展现一个方法
public void SendEmailAsync(Message model) { Task.Run(() => { try { var reclist = string.Empty; foreach (var item in model.RecUser.Split(',')) { var userinfo = this.UserRepository.GetbyID(int.Parse(item)); //这里就调用了实现接口的那个类的方法,去验证用户的ID if (!string.IsNullOrEmpty(userinfo.Email)) { reclist += userinfo.Email + ","; } } if (!string.IsNullOrEmpty(reclist)) { reclist = reclist.Substring(0, reclist.Length - 1); EmailHelper email = new EmailHelper(reclist, model.MessageTitle, model.MessageText); email.Send(); } model.SendEmailState = 2; this.MessageServer.SetSendState(model); }catch(Exception ex){ new LogHelper().LogError("发送邮件异常" + ex); model.SendEmailState = 3; this.MessageServer.SetSendState(model); } }); }
那么整个流程就是这样,看着别人写的那些博客里面的流程不是那么的全面,我这里就详细的把AutoFac的整个流程给梳理出来了,有不对的地方请及时指出
后面我会详细说明一下Unity IOC框架是如何使用的,这里我就再也不叙述了
下面是两篇比较好的博文,我以为比较有参考意义的,能够看一下,喜欢我发布的内容的能够关注我,后面还会有其余的干货和内容进行分享
.NET领域最为流行的IOC框架之一Autofac:https://www.cnblogs.com/yinrq/p/5381492.html
.NET Unity IOC框架使用实例:https://blog.csdn.net/chen_peng7/article/details/54896449
C#特性详解
特性(attribute)是被指定给某一声明的一则附加的声明性信息。
在C#中,有一个小的预约义特性集合。在学习如何创建咱们本身的定制特性(custom attributes)以前,咱们先来看看在咱们的代码中如何使用预约义特性。
1 using System; 2 public class AnyClass 3 { 4 [Obsolete("Don't use Old method, use New method", true)] 5 static void Old( ) { } 6 static void New( ) { } 7 public static void Main( ) 8 { 9 Old( ); 10 } 11 }
咱们先来看一下上面这个例子,在这个例子中咱们使用了Obsolete特性,它标记了一个不该该再被使用的程序实体。第一个参数是一个字符串,它解释了为何该实体是过期的以及应该用什么实体来代替它。实际上,你能够在这里写任何文本。第二个参数告诉编译器应该把使用这个过期的程序实体看成一种错误。它的默认值是false,也就是说编译器对此会产生一个警告。
当咱们尝试编译上面这段程序的时候,咱们将会获得一个错误:
AnyClass.Old()' is obsolete: 'Don't use Old method, use New method'
开发定制特性(custom attributes)
如今让咱们来看看如何开发咱们本身的特性。
首先咱们要从System.Attribute派生出咱们本身的特性类(一个从System.Attribute抽象类继承而来的类,无论是直接仍是间接继承,都会成为一个特性类。特性类的声明定义了一种能够被放置在声明之上新的特性)。
1 using System; 2 public class HelpAttribute : Attribute 3 { 4 }
无论你是否相信,咱们已经创建了一个定制特性,如今咱们能够用它来装饰现有的类就好像上面咱们使用Obsolete attribute同样。
1 [Help()] 2 public class AnyClass 3 { 4 }
注意:对一个特性类名使用Attribute后缀是一个惯例。然而,当咱们把特性添加到一个程序实体,是否包括 Attribute后缀是咱们的自由。编译器会首先在System.Attribute的派生类中查找被添加的特性类。若是没有找到,那么编译器会添加 Attribute后缀继续查找。
到目前为止,这个特性尚未起到什么做用。下面咱们来添加些东西给它使它更有用些。
1 using System; 2 public class HelpAttribute : Attribute 3 { 4 public HelpAttribute(String Descrition_in) 5 { 6 this.description = Description_in; 7 } 8 protected String description; 9 public String Description 10 { 11 get 12 { 13 return this.description; 14 } 15 } 16 } 17 [Help("this is a do-nothing class")] 18 public class AnyClass 19 { 20 }
在上面的例子中,咱们给HelpAttribute特性类添加了一个属性而且在后续的部分中咱们会在运行时环境中查寻它。
定义或控制特性的使用
AttributeUsage类是另一个预约义特性类,它帮助咱们控制咱们本身的定制特性的使用。它描述了一个定制特性如和被使用。
AttributeUsage有三个属性,咱们能够把它放置在定制属性前面。第一个属性是:
ValidOn
经过这个属性,咱们可以定义定制特性应该在何种程序实体前放置。一个属性能够被放置的全部程序实体在AttributeTargets enumerator中列出。经过OR操做咱们能够把若干个AttributeTargets值组合起来。
AllowMultiple
这个属性标记了咱们的定制特性可否被重复放置在同一个程序实体前屡次。
Inherited
咱们可使用这个属性来控制定制特性的继承规则。它标记了咱们的特性可否被继承。
下面让咱们来作一些实际的东西。咱们将会在刚才的Help特性前放置AttributeUsage特性以期待在它的帮助下控制Help特性的使用。
1 using System; 2 [AttributeUsage(AttributeTargets.Class), AllowMultiple = false, 3 Inherited = false ] 4 public class HelpAttribute : Attribute 5 { 6 public HelpAttribute(String Description_in) 7 { 8 this.description = Description_in; 9 } 10 protected String description; 11 public String Description 12 { 13 get 14 { 15 return this.description; 16 } 17 } 18 }
先让咱们来看一下AttributeTargets.Class。它规定了Help特性只能被放在class的前面。这也就意味着下面的代码将会产生错误:
1 [Help("this is a do-nothing class")] 2 public class AnyClass 3 { 4 [Help("this is a do-nothing method")] //error 5 public void AnyMethod() 6 { 7 } 8 }
编译器报告错误以下:
AnyClass.cs: Attribute 'Help' is not valid on this declaration type.
It is valid on 'class' declarations only.
咱们可使用AttributeTargets.All来容许Help特性被放置在任何程序实体前。可能的值是:
Assembly,Module,Class,Struct,Enum,Constructor,Method,Property,Field,Event,Interface,Parameter,Delegate
All = Assembly | Module | Class | Struct | Enum | Constructor | Method | Property | Field | Event | Interface | Parameter | Delegate
ClassMembers = Class | Struct | Enum | Constructor | Method | Property | Field | Event | Delegate | Interface
下面考虑一下AllowMultiple = false。它规定了特性不能被重复放置屡次。
1 [Help("this is a do-nothing class")] 2 [Help("it contains a do-nothing method")] 3 public class AnyClass 4 { 5 [Help("this is a do-nothing method")] //error 6 public void AnyMethod() 7 { 8 } 9 }
它产生了一个编译期错误。
AnyClass.cs: Duplicate 'Help' attribute
Ok,如今咱们来讨论一下最后的这个属性。Inherited, 代表当特性被放置在一个基类上时,它可否被派生类所继承。
1 [Help("BaseClass")] 2 public class Base 3 { 4 } 5 public class Derive : Base 6 { 7 }
这里会有四种可能的组合:
1 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false ] 2 [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false ] 3 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true ] 4 [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true ]
第一种状况:
若是咱们查询(Query)(稍后咱们会看到如何在运行期查询一个类的特性)Derive类,咱们将会发现Help特性并不存在,由于inherited属性被设置为false。
第二种状况:
和第一种状况相同,由于inherited也被设置为false。
第三种状况:
为了解释第三种和第四种状况,咱们先来给派生类添加点代码:
1 [Help("BaseClass")] 2 public class Base 3 { 4 } 5 [Help("DeriveClass")] 6 public class Derive : Base 7 { 8 }
如今咱们来查询一下Help特性,咱们只能获得派生类的属性,由于inherited被设置为true,可是AllowMultiple却被设置为false。所以基类的Help特性被派生类Help特性覆盖了。
第四种状况:
在这里,咱们将会发现派生类既有基类的Help特性,也有本身的Help特性,由于AllowMultiple被设置为true。
定义或控制特性的使用AttributeUsage类是另一个预约义特性类,它帮助咱们控制咱们本身的定制特性的使用。它描述了一个定制特性如何被使用。
属性和特性的区别能够参考一下: http://developer.51cto.com/art/200908/147097.htm
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Foxalien/archive/2009/12/05/4946672.aspx
C#特性详解
特性(attribute)是被指定给某一声明的一则附加的声明性信息。
在C#中,有一个小的预约义特性集合。在学习如何创建咱们本身的定制特性(custom attributes)以前,咱们先来看看在咱们的代码中如何使用预约义特性。
1 using System; 2 public class AnyClass 3 { 4 [Obsolete("Don't use Old method, use New method", true)] 5 static void Old( ) { } 6 static void New( ) { } 7 public static void Main( ) 8 { 9 Old( ); 10 } 11 }
咱们先来看一下上面这个例子,在这个例子中咱们使用了Obsolete特性,它标记了一个不该该再被使用的程序实体。第一个参数是一个字符串,它解释了为何该实体是过期的以及应该用什么实体来代替它。实际上,你能够在这里写任何文本。第二个参数告诉编译器应该把使用这个过期的程序实体看成一种错误。它的默认值是false,也就是说编译器对此会产生一个警告。
当咱们尝试编译上面这段程序的时候,咱们将会获得一个错误:
AnyClass.Old()' is obsolete: 'Don't use Old method, use New method'
开发定制特性(custom attributes)
如今让咱们来看看如何开发咱们本身的特性。
首先咱们要从System.Attribute派生出咱们本身的特性类(一个从System.Attribute抽象类继承而来的类,无论是直接仍是间接继承,都会成为一个特性类。特性类的声明定义了一种能够被放置在声明之上新的特性)。
1 using System; 2 public class HelpAttribute : Attribute 3 { 4 }
无论你是否相信,咱们已经创建了一个定制特性,如今咱们能够用它来装饰现有的类就好像上面咱们使用Obsolete attribute同样。
1 [Help()] 2 public class AnyClass 3 { 4 }
注意:对一个特性类名使用Attribute后缀是一个惯例。然而,当咱们把特性添加到一个程序实体,是否包括 Attribute后缀是咱们的自由。编译器会首先在System.Attribute的派生类中查找被添加的特性类。若是没有找到,那么编译器会添加 Attribute后缀继续查找。
到目前为止,这个特性尚未起到什么做用。下面咱们来添加些东西给它使它更有用些。
1 using System; 2 public class HelpAttribute : Attribute 3 { 4 public HelpAttribute(String Descrition_in) 5 { 6 this.description = Description_in; 7 } 8 protected String description; 9 public String Description 10 { 11 get 12 { 13 return this.description; 14 } 15 } 16 } 17 [Help("this is a do-nothing class")] 18 public class AnyClass 19 { 20 }
在上面的例子中,咱们给HelpAttribute特性类添加了一个属性而且在后续的部分中咱们会在运行时环境中查寻它。
定义或控制特性的使用
AttributeUsage类是另一个预约义特性类,它帮助咱们控制咱们本身的定制特性的使用。它描述了一个定制特性如和被使用。
AttributeUsage有三个属性,咱们能够把它放置在定制属性前面。第一个属性是:
ValidOn
经过这个属性,咱们可以定义定制特性应该在何种程序实体前放置。一个属性能够被放置的全部程序实体在AttributeTargets enumerator中列出。经过OR操做咱们能够把若干个AttributeTargets值组合起来。
AllowMultiple
这个属性标记了咱们的定制特性可否被重复放置在同一个程序实体前屡次。
Inherited
咱们可使用这个属性来控制定制特性的继承规则。它标记了咱们的特性可否被继承。
下面让咱们来作一些实际的东西。咱们将会在刚才的Help特性前放置AttributeUsage特性以期待在它的帮助下控制Help特性的使用。
1 using System; 2 [AttributeUsage(AttributeTargets.Class), AllowMultiple = false, 3 Inherited = false ] 4 public class HelpAttribute : Attribute 5 { 6 public HelpAttribute(String Description_in) 7 { 8 this.description = Description_in; 9 } 10 protected String description; 11 public String Description 12 { 13 get 14 { 15 return this.description; 16 } 17 } 18 }
先让咱们来看一下AttributeTargets.Class。它规定了Help特性只能被放在class的前面。这也就意味着下面的代码将会产生错误:
1 [Help("this is a do-nothing class")] 2 public class AnyClass 3 { 4 [Help("this is a do-nothing method")] //error 5 public void AnyMethod() 6 { 7 } 8 }
编译器报告错误以下:
AnyClass.cs: Attribute 'Help' is not valid on this declaration type.
It is valid on 'class' declarations only.
咱们可使用AttributeTargets.All来容许Help特性被放置在任何程序实体前。可能的值是:
Assembly,Module,Class,Struct,Enum,Constructor,Method,Property,Field,Event,Interface,Parameter,Delegate
All = Assembly | Module | Class | Struct | Enum | Constructor | Method | Property | Field | Event | Interface | Parameter | Delegate
ClassMembers = Class | Struct | Enum | Constructor | Method | Property | Field | Event | Delegate | Interface
下面考虑一下AllowMultiple = false。它规定了特性不能被重复放置屡次。
1 [Help("this is a do-nothing class")] 2 [Help("it contains a do-nothing method")] 3 public class AnyClass 4 { 5 [Help("this is a do-nothing method")] //error 6 public void AnyMethod() 7 { 8 } 9 }
它产生了一个编译期错误。
AnyClass.cs: Duplicate 'Help' attribute
Ok,如今咱们来讨论一下最后的这个属性。Inherited, 代表当特性被放置在一个基类上时,它可否被派生类所继承。
1 [Help("BaseClass")] 2 public class Base 3 { 4 } 5 public class Derive : Base 6 { 7 }
这里会有四种可能的组合:
1 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false ] 2 [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false ] 3 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true ] 4 [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true ]
第一种状况:
若是咱们查询(Query)(稍后咱们会看到如何在运行期查询一个类的特性)Derive类,咱们将会发现Help特性并不存在,由于inherited属性被设置为false。
第二种状况:
和第一种状况相同,由于inherited也被设置为false。
第三种状况:
为了解释第三种和第四种状况,咱们先来给派生类添加点代码:
1 [Help("BaseClass")] 2 public class Base 3 { 4 } 5 [Help("DeriveClass")] 6 public class Derive : Base 7 { 8 }
如今咱们来查询一下Help特性,咱们只能获得派生类的属性,由于inherited被设置为true,可是AllowMultiple却被设置为false。所以基类的Help特性被派生类Help特性覆盖了。
第四种状况:
在这里,咱们将会发现派生类既有基类的Help特性,也有本身的Help特性,由于AllowMultiple被设置为true。
定义或控制特性的使用AttributeUsage类是另一个预约义特性类,它帮助咱们控制咱们本身的定制特性的使用。它描述了一个定制特性如何被使用。
属性和特性的区别能够参考一下: http://developer.51cto.com/art/200908/147097.htm
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Foxalien/archive/2009/12/05/4946672.aspx
WPF 可触摸移动的ScrollViewer控件
ListBox支持触摸滑动,而ScrollViewer默认不支持。
ScrollViewer如须要添加上下/左右触摸移动,须要在Touch事件中处理。
处理以下:封装成一个用户控件
- TouchDown事件中记录起始点,并添加对TouchMove事件的监听
- TouchUp事件中注销TouchMove事件的监听
- 在TouchMove事件中,处理移动的偏移量。起始位置减去偏移量,即为当前滚动条的位置。
注:ScrollViewer滚动到指定位置(指定位置=起始位置-移动的偏移量,滚动方向和手势方向相反)
1 /// <summary> 2 /// 可触摸滚动的ScrollViewer控件 3 /// </summary> 4 public class TouchableScrollViewer : ScrollViewer 5 { 6 //触摸点的坐标 7 Point _startPosition; 8 //滚动条当前位置 9 double _startVerticalOffset; 10 double _startHorizontalOffset; 11 public TouchableScrollViewer() 12 { 13 TouchDown += TouchableScrollViewer_TouchDown; 14 15 TouchUp += TouchableScrollViewer_TouchUp; 16 } 17 private void TouchableScrollViewer_TouchDown(object sender, TouchEventArgs e) 18 { 19 //添加触摸移动监听 20 TouchMove -= TouchableScrollViewer_TouchMove; 21 TouchMove += TouchableScrollViewer_TouchMove; 22 23 //获取ScrollViewer滚动条当前位置 24 _startVerticalOffset = VerticalOffset; 25 _startHorizontalOffset = HorizontalOffset; 26 27 //获取相对于ScrollViewer的触摸点位置 28 TouchPoint point = e.GetTouchPoint(this); 29 _startPosition = point.Position; 30 } 31 32 private void TouchableScrollViewer_TouchUp(object sender, TouchEventArgs e) 33 { 34 //注销触摸移动监听 35 TouchMove -= TouchableScrollViewer_TouchMove; 36 } 37 38 private void TouchableScrollViewer_TouchMove(object sender, TouchEventArgs e) 39 { 40 //获取相对于ScrollViewer的触摸点位置 41 TouchPoint endPoint = e.GetTouchPoint(this); 42 //计算相对位置 43 double diffOffsetY = endPoint.Position.Y - _startPosition.Y; 44 double diffOffsetX = endPoint.Position.X - _startPosition.X; 45 46 //ScrollViewer滚动到指定位置(指定位置=起始位置-移动的偏移量,滚动方向和手势方向相反) 47 ScrollToVerticalOffset(_startVerticalOffset - diffOffsetY); 48 ScrollToHorizontalOffset(_startHorizontalOffset - diffOffsetX); 49 } 50 }
Demo下载
.NET(C#)能开发出什么样的APP?盘点那些经过Smobiler开发的移动应用
.NET程序员必定最熟悉所见即所得式开发,熟悉的Visual Studio开发界面,熟悉的C#代码。
Smobiler也是由于具有这样的特性,使开发人员,能够在VisualStudio上,像开发WinForm同样拖拉控件,让许多人在开发APP时,再次回到所见即所得的开发方式中去。
Smobiler的快速开发,让Amanda看到了程序员们分享的各式各样的应用。
一
来自程序员的分享
👆产线物料管理类的应用
实时监控产线物料状况
社区物业管理类的应用👇
方便社区居民在线查询、缴费
👆公益社区类的应用
为公益热心者提供一个线上社区
企业内部OA管理应用👇
请假、工做流、报销等功能
以上截图均来自Smobiler技术开发群用户的分享
二
一千个应用有一千种界面
在“家庭小秘”没出现以前,咱们也是想不到会有用户愿意在UI上投入资源,作出出这样简洁好看的界面。
家庭小秘APP
毕竟咱们见到更多的是企业类应用,对UI界面要求没那么高,功能至上。
好比这个花了十来天作的企业内部管理应用:
一款为练手而作的APP
这只是练手之做,我们先把后端的业务代码跑通,UI设计什么的,正式项目里,交给专业的设计师会更省事。
专业的和业余虽然都能把意思表达出来,但区别就跟下面这张图同样:
三
官方推出的三款开源APP
Smobiler官方也前后推出了三款开源的应用,应用的源代码已经托管至GitHub,这三款应用分别是
SmoONE:开源的移动OA应用
包含了GPS定位、IM等功能
SmoSEC:开源的资产管理移动应用
包含了条码扫描、RFID扫描等功能
SmoWMS:开源的仓库管理移动应用
包含仓库管理中的基本核心功能,固然仓库管理中的条码扫描、RFID扫描等也是不可少的
(文末有这三款应用源代码的获取方式。)
重点是,这三款应用的代码,都是
免费!开源的!
你能够把源码下载下来,而后根据项目的需求,进行二次开发。好比这样
左图是SmoONE的界面,右图是用户在SmoONE源码基础上的修改
好比这样:
左图是SmoWMS的界面,右图是用户在SmoWMS源码基础上的修改
这样的界面从零作起,总共只分三步,大概须要两分钟吧:
第一步:拖拉控件
第二步:设置title和toolbar属性
第三步:设置iconmenuview属性和启动程序
最后作什么样的APP,彻底看项目须要,和程序员的心情,以及……客户是否介意你依照本身的喜爱作出来的界面。
作项目嘛,最重要的是效率;敲代码嘛,最重要的就是开心。
四
三款开源项目的获取方式
在GitHub上搜索
“SmoONE”、“SmoSEC”、“SmoWMS”
即可找到。
也可复制如下地址至浏览器直接前往获取。
SmoONE 移动OA应用
https://github.com/comsmobiler/SmoONE
包含了GPS定位、IM等功能
SmoSEC 资产管理移动应用
https://github.com/comsmobiler/SmoSEC
资产管理移动应用,包含了条码扫描、RFID扫描等功能
SmoWMS 仓库管理移动应用
https://github.com/comsmobiler/SmoWMS
包含仓库管理中的基本核心功能,固然仓库管理中的条码扫描、RFID扫描等也是不可少的
.NET移动开发,关于发布IOS的方法(本人亲身经历折腾好久终于成功)
前情提要:这位.NET程序员兄弟使用Smobiler开发了一个APP,尽管Smobiler云平台已经最大限度的简化了iOS应用的打包操做,但仍绕不开苹果公司强制要求的p12文件,p12文件须要开发者自行生成,在此,qio763分享了这次生成p12文件的经验,不管是初学iOS原生开发,仍是.NET移动开发平台的smobiler,在生成iOS安装包以前,p12文件生成这一步都是必经之路。
(P.S.提交了正确的p12文件后,应用已成功打包)
----------------------------------如下为原文----------------------------------
在发布IOS版本前,须要作的准备工做:
本人使用的虚拟主机,版本为10.12(但不支持xcode10有点尴尬),若是你使用的MAC系统,能够直接操做,虚拟主机方面请自行百度,此处不讲
第一步,生成一个你的我的证书(钥匙串)
第二步:进入IOS开发者中心进行相关的设置(此处很是重要,不少人包括我本人都出现了错误)
点击Certificates下的all弹出的菜单中点击+号,新添加一个你的我的证书,如已有证书可跳过此步
须要注意此步聚很重要,此处必须选择红框部分,由于smo发布要求发布正式版本,因此须要选择此项,而后点击continue直到出现如下画面
点击红框部分,选择刚才咱们使用钥匙串申请的文件
完成后点击download下载到本地,双击刚下载的证书,将其导入到钥匙串中
添加完成后,咱们须要将证书生成P12我的证书,这也是smo所须要的证书,咱们在钥匙串中请行如下操做
右键点击咱们刚才添加的证书,选择导出证书
导出证书时,文件格式默认为P12,咱们就不要动了,也不要去管他,默认就好。
导出证书时需填写一个你的导出密码,这个密码能够随意设置,但必须牢记,对应smobier中的导出密码
到此,证书部分就算是完成了,企业证书原理同样,操做方法也是这样。下面是建立咱们的APPID与咱们的发布描述。
发布描述部分相对比较麻烦,不少用户出错基本都在这里出错(我本身在这出错好几回)
发布描述,首先须要建立APPID
Identifiers》appids中点击+号
须要注意的是BundleID必须与你的smobier的应用包名一致,若是不一致将没法正常打包
必须勾选Push Notifications选项,包含了推送信息,而后点击继续按钮直到完成
点击刚建立的appid弹出详细信息,咱们会发现,该功能并无应用,咱们点击edit进行编辑
咱们会发现,关于Push Notifications部分有两个选项,其实一个是测试版,一个是正式版,咱们这里选择正式版并建立,点击继续按钮进入选择页面
点击选择按钮,咱们选择,咱们最开始用钥匙串生成的文件,点击继续完成appid Push Notifications的修改,至此,appid建立完成,接下来就是发布描述文件的生成了
Provisioning Profiles→Distribution
点击Distribution中的+号
在此处咱们选择正式版,也就是红色框部分,点击继续
此处选择,咱们刚才建立的appid,此ID对应的是咱们的smobiler的包名
选择咱们第一步建立的证书,点击继续,完成发布描述,点击download下载咱们的发布描述文件
咱们在smobiler的应用平台发布IOS时,就将咱们刚才生成的P12文件上传,密码填写咱们导出P12证书的密码,将下载的发布描述文件上传后,就能够完成IOS的打包了
打包IOS很重要,特别是你的插件,若是包名错误了,再删除是很难恢复的,个人插件就是由于打包操做出现问题就没有了,很难过
做者:qio763
(原帖地址:https://www.smobiler.com/forum.php?mod=viewthread&tid=11605)