Sql2012如何将远程服务器数据库及表、表结构、表数据导入本地数据库 自定义日志记录功能,按日记录,很方便 C#常量和字段以及各种方法的语法总结 类型,对象,线程栈,托管堆在运行时的关系,以及clr如何调用静态方法,实例方法,和虚方法 asp.net webapi 自定义身份验证
Sql2012如何将远程服务器数据库及表、表结构、表数据导入本地数据库
1、第一步,在本地数据库中建一个与服务器同名的数据库
2、第二步,右键源数据库,任务》导出数据,弹出导入导出提示框,点下一步继续
3、远程数据库操作,确认服务器名称(服务器地址)、身份验证(输入用户名、密码)、选择需要导出的源数据库,点下一步继续
4、本地目标服务器操作,确认服务器名称、输入用户名密码、选择要导入的目标数据库(一般与远程数据库同名),点下一步继续
5、这一步选择默认,点下一步继续
6、选择需要复制的表或视图(一般全选就是),点下一步继续
7、选择默认,点下一步继续
8、选择完成,执行表结构及表数据复制过程,表及数据复制过程
9、到这一步,表示整个过程执行成功
自定义日志记录功能,按日记录,很方便
一、定义日志类型
public enum LogType
{
Debug = 0,
Error = 1,
Info = 2,
Warn = 3
}
二、添加静态LogHelper 类
public static class LogHelper
{
public static void Write(string msg, LogType logtype = LogType.Debug)
{
try
{
string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs");
Directory.CreateDirectory(basePath);
string logPath = Path.Combine(basePath, DateTime.Today.ToString("yyyyMMdd") + ".log");
using (FileStream stream = new FileStream(logPath, FileMode.Append, FileAccess.Write, FileShare.Read))
{
using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8))
{
string messge = string.Format("{0} {1} - 操作人:【{2}】,Messge:{3}",
DateTime.Now.ToString(), logtype.ToString(), DeluxeIdentity.Current.User.DisplayName,msg);
writer.WriteLine(messge);
writer.Flush();
}
}
}
catch (Exception e)
{
throw new Exception( "日志写入异常:" + e.ToString());
}
}
}
三、调用方法
LogHelper.Write("检测拟单页面审批意见是否重复保存异常,原因:" + e.ToString(), LogType.Error);
四、效果
C#常量和字段以及各种方法的语法总结
目录
一、 常量和字段.... 1
1、 常量.... 1
2、字段.... 1
二、方法.... 2
1、实例构造器和类(引用类型).... 2
2、 实例构造器和结构(值类型).... 2
3、 类型构造器.... 3
4、 操作符重载方法.... 3
5、 转换操作符方法.... 3
6、 扩展方法.... 4
三、参数.... 5
1、可选参数和命名参数... 5
2、以引用的方式向方法传递参数.... 5
3、向方法传递可变数量的参数... 6
4、参数和返回类型的设计规范... 6
一、常量和字段
1、 常量
常量使用const标记,表示值恒定不变的符号。可以用c#内置的基元类型和引用为null的引用类型赋值。
优点:
- 编译的时候就确定,所以运行很快,编译器在检测到const标识的时候就使用计算好的值代替,生成元数据,在运行的时候Jit二次编译的时候会从元数据中找到值,嵌在机器码里面。所以值类型不会在运行时,加载程序集和动态分配内存。不存在引用。
缺点:
- 正是因为以上的优点,所以值类型在处理不同程集的时候,会存在版本控制的问题,因为改了值类型的值以后,另外一个程序集,不会再运行时重新编译的。
2、字段
1、类型字段,实例字段,只读字段(static,默认,readOnly)
类型字段在类型对象中分配内存,类型对象是类型加载到AppDoMain时候创建的,什么时候类型加载到AppDoMain? 通常是引用了该类型的任何方法首次进行Jit编译的时候。
2、字段的内联初始化只是语法上的简化(上图),C#编译器还是会把他们在构造函数中初始化。
3、引用类型的readOnly字段不能变的是引用的地址,而不是引用变量对象的值。
二、方法
1、实例构造器和类(引用类型)
创建引用类型的实例,首先分派类型字段内存,然后初始化对象的附加字段(类型对象指针和同步块索引),最后调用类型对象的实例构造器(初始化字段,调用基类的构造函数,执行自己的代码)。
A、 C#会默认生成类型的无参数构造函数,如果手动写了有参数的构造器,则不会生成。即使类的修饰符是abstract,也会生成默认的protected的无参数构造函数(当然可以手动指定public),如果是静态类,C#编译器根本不会再类中生成默认的无参数构造函数,在访问从基类继承来的任何字段之前,必须先调用基类的构造函数,如果没有显示调用,C#编译器也会生成代码自动调用基类的无参数构造函数,最终System.Object的构造函数会被调用。
2、 实例构造器和结构(值类型)
Clr总是允许创建值类型的实例,并且没有办法阻止值类型实例化,所以值类型需要也不会定义无参数构造函数。如果一个值类型在引用类型里面作为变量使用,处于性能考虑,C#不会为每个执行类性显示调用其构造函数,但是会在使用前初始化值类型。
如果指定了构造函数那必须为所有的字段初始化,否则会报错。
3、 类型构造器
1、类型构造器用于初始化类型的状态,类型默认没有定义类型构造器,如果定义的话也只能定义一个无参数的。
对类型构造器的调用总是由Clr亲自调用的,所以类型构造器访问修饰符是private但是不能手动指定,c#编译器默认加上。
适用于引用类型和值类型(永远别在值类型中定义类型构造器)
2、调用过程
类型构造器的调用比较麻烦,JIT在编译一个方法的时候,会检查方法中的所有引用,如果有的类定义了类型构造器,Jit就会在appDoMain中检查,是否已经调用过类型构造器,调用过了就不在调用。
Internal sealed class SomeRefType
{
Static SomeRefType()
{
}
}
4、 如果类型构造器抛出未处理的,Clr会认为类型不可用。视图访问该类型的任何字段或者方法都会抛出System.InitializationException。
4、 操作符重载方法
Clr要求操作符重载必须是Public static 只少有一个参数类型是方法的定义类型,编译器会生成一个op_*的方法,该方法有个specialname标志,C#编译器看到源码中+操作符的时候,会检查操作数的类型是否定义了名为op_addition的specialname,而且方法的参数是否兼容操作数的类型,如果存在就生成方法调用,否则就报错。
Public static Int32 operator +(ClassName c1,ClassName c2)
{
}
5、 转换操作符方法
Public static implicit operator Int32(Person person)
{
Return 10;
}
6、 扩展方法
它允许定义一个静态方法,并用实例方法的语法来调用。
扩展方法必须在非泛型的静态类中声名。
C#编译器在静态类中查找扩展方法时,必须在文件作用域,而不是嵌套类。
使用扩展方法发扩展一个类型同时也扩展了派生类型。所以不要在System.Object上扩展。
扩展方法实际上是静态方法,所以不会Clr对调用者进行null值检查。(下面的代码可以正常运行,但是有可能在方法的内部抛出null异常)
Public static class StringBuilderExtensions
{
Public static Int32 IndexOf(this StringBuilder sb,Char value)
{
For(Int32 i=0,i<sb.Length;i++)
{
If(sb[i]==value)return I;
Return -1;
}
}
}
编译器找扩展方法的顺序:
首先StringBuilder类或者它的基类是否提供了参数类型为Char 名称为IndexOf的方法,如果有就生成IL代码来调用。如果没有找到匹配的实例方法,就继续检查是否有任何静态类定义了IndexOf的静态方法,方法的第一个参数的类型和当前的调用类型一致且使用this修饰。
为接口提供扩展
Public static class IEnumerableExtensions
{
Public static void ShowItem<T>(this IEnumerable collection)
{
Foreach(var item in collection)
{
Console.WriteLine(item);
}
}
}
为委托定义扩展
Public static class ActionExtentsions
{
Public static void InvokeAndCatch(this Action<Object> ac,Object o)
{
Ac(o);
}
}
Action<Object> action=o=>Console.WriteLine(o.GetType());
Action.InokeAndCatch(null);
使用委托来引用对象上的扩展方法:
Action a=”Wupo”.ShowItems;
a.InVoke();
调用委托实例 翻译成 唤出比较合适invoke
调用对象方法,叫调用 call
Invoke 是需要唤出某个东西来帮你调用一个信息不明确的方法时,
Call 是知道了方法的名称 参数类型 返回值 等。
三、参数
1、可选参数和命名参数
设计方法的参数,可为部分参数分配默认值,然后调用这些方法的代码可以选择不提供部分参数,使用其默认值。
默认值在参数列表的右边,可选参数,在最后且不能有默认值。
默认值可以是 基元类型,枚举,为null的引用类型。
如果参数使用ref 、out标识就不能设置默认值。
2、以引用的方式向方法传递参数
Clr默认所用的参数都是传值。传递引用类型的时候,对象的引用(对象指针)被传递给方法,指针本身是传值的。对于值类型,传递给方法的是实例的一个副本。调用者本身不收影响。
Clr允许以传引用的方式传递参数,使用out ref关键字,告诉C#编译器生成元数据来指明参数是传引用的,编译器将生成代码来传递参数的地址。
Clr本身不区分out 和ref,生成的IL代码也差不多,只有一个bit标准符不同个,用以表明方法指定的是out还是ref.不同之处是这个标志符绝定了由哪个方法负责初始化引用的对象。 如果方法使用out 来标记 则表明不指望(但是可以)调用者在调用之前就初始化,被调用的方法不能读取参数的值,而且在放回之前必须向这个值写入。相反如果方法使用ref来标记,调用者必须在调用方法之前就必须把参数初始换,被调用的方法可以读取和写入值。
Clr允许根据使用out ref对方法进行重载。
但是不允许仅在out 和ref个有不同的方法进行重载。
对于以引用方式传递给方法的变量,它的类型必须与方法签名中声名的类型相同,否则无法编译,可以使用泛型解决这个问题。
3、向方法传递可变数量的参数
可变参数只能放在方法签名的最后。
Static Int32 Add(params Int32[] values)
{
}
由于有params关键字,所以编译器向参数应用定制特性System.ParamArrayAttribute,C#编译器检测到方法调用,会先检查具有指定名称,同时参数没有应用ParamArrayAttribute特性的方法,找到就生成调用代码。没有找到就会检查使用了ParamArrayAttribute的方法,找到以后编译器先生成代码来构造一个数组,填充它的元素,在生成代码来调用它。
4、参数和返回类型的设计规范
声名参数的类型是,应尽量指定最弱类型,宁愿要接口也不要基类。
IEnumerable<T> 比List<T>好,如果方法需要列表,使用Ilist<T> 也比List<T>好。
类型,对象,线程栈,托管堆在运行时的关系,以及clr如何调用静态方法,实例方法,和虚方法
1、线程栈
window的一个进程加载clr。该进程可能含有多个线程,线程创建的时候会分配1MB的栈空间。
如图:
void Method()
{
string name="zhangsan"; //name 被放入栈里面
Method2(name); //1参数变量s 被压入栈,s引用name的地址 2.返回地址被压入栈,方法执行完(method2的 return)指针指向此返回地址
return;
}
void Method2(string s)
{
int32 length=s.Length;
int32 tally;
return; //methed2执行完后,指针指向线程栈的返回地址,method2的栈帧展开
}
2.运行时关系
现有如下2个类型
internal class Employee
{
public int32 M1(){.....};
public virtual string M2(){.....};
public static Employee M3(string name){.....};
}
internal sealed class Manager:Employee
{
public override string M2(){.....};
}
准备:window进程已经开启,clr已经加载到进程里面,托管堆已经初始化,线程栈也已经被创建(连同它的1MB的栈空间)
void M4()
{
Employee e;
int32 age;
e=new Manager();
e=Employee.M3("zhangsan");
age=e.M1();
e.M2();
}
a.首先介绍下new 关键字的执行的时候会执行什么
1.clr计算出类型的所有实例字段的字节和所有基类型的实例字段的字节长度,创建类型对象指针和同步块索引(也计算在字节长度内)
2.在托管堆上分配第一步长度的空间
3.初始化类型对象指针(指向类型对象)和同步块索引
4.调用类型的实例构造器。
b.运行关系图
c.详细解释
1.M4运行的时候 先在线程栈 压入e和age两个局部变量
2.e=new Manager();会在托管推上分配Manager和所有基类的实例字段字节大小,初始化类型对象指针,指向Manager类型对象。
3 Employee.M3("zhangsan"); 第一个对象将被垃圾回收器回收。他会找到调用它的类型,然后去类型对象的方法列表中找到这个方法,
然后JIT进行编译,然后执行。
4.e.M1();找到e对象类型对应的对象类型Manager(没有,回溯到Employee中找),在方法列表中找到对应的方法,编译执行(能够向上回溯是因为在派生类中有指向基类的引用)
5.e.M2()找到e对象的的对象类型(Manager),调用Manager类型对象方法列表中的M2 而不是Employee中的。
asp.net webapi 自定义身份验证
/// <summary> /// 验证 /// </summary> /// Account API账号 /// TimeStamp 请求时间 /// Sign 所有请求参数 加密 public class AuthFilterOutside : AuthorizeAttribute { //重写基类的验证方式,加入我们自定义的Ticket验证 public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext) { //url获取token var content = actionContext.Request.Properties["MS_HttpContext"] as HttpContextBase; string account = content.Request.QueryString["Account"]; string sign = content.Request.QueryString["Sign"]; int timeStamp = 0; int.TryParse(content.Request.QueryString["TimeStamp"], out timeStamp); ApiInfo apiInfo = DB.GetApiInfo(account); int nowTimeStamp = Convert.ToInt32(GenerateTimeStamp()); // 无效请求 if (apiInfo == null || nowTimeStamp - timeStamp > 15) { HandleUnauthorizedRequest(actionContext); return; } SortedDictionary<string, string> dic = new SortedDictionary<string, string>(); foreach (string key in content.Request.QueryString.AllKeys) { if (key != "sign") { dic.Add(key, content.Request.QueryString[key]); } } string makeSign = GetMakeSign(dic, apiInfo.Token); // 签名不正确 if (sign != makeSign) { HandleUnauthorizedRequest(actionContext); return; } } protected override void HandleUnauthorizedRequest(HttpActionContext filterContext) { base.HandleUnauthorizedRequest(filterContext); var response = filterContext.Response = filterContext.Response ?? new HttpResponseMessage(); response.StatusCode = HttpStatusCode.Forbidden; string str = "{\"success\":\"false\",\"message\":\"服务端拒绝访问:您没有权限!\"}"; response.Content = new StringContent(str, Encoding.UTF8, "application/json"); } public static string GenerateTimeStamp() { TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); return Convert.ToInt64(ts.TotalSeconds).ToString(); } /// <summary> /// 所有参数 ascii码排序 最后追加Key /// </summary> /// <param name="dic"></param> /// <param name="token"></param> /// <returns></returns> public string GetMakeSign(SortedDictionary<string, string> dic, string token) { StringBuilder strBuilder = new StringBuilder(); foreach (var item in dic) { strBuilder.AppendFormat("{0}={1}&", item.Key, item.Value); } strBuilder.AppendFormat("key={0}", token); var md5 = MD5.Create(); var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(strBuilder.ToString())); var sb = new StringBuilder(); foreach (byte b in bs) { sb.Append(b.ToString("x2")); } //所有字符转为大写 return sb.ToString().ToUpper(); } }