• [技术干货] java面试题基础篇 温故而知新 没事在地铁上多看看
    答案在路上,自由在风里,风吹哪页读哪页,哪页不懂撕哪页就是你,你太棒啦今天也要开开心心呀Java语言有哪些特点Java是一种高级编程语言,具有以下特点:面向对象:Java是一种纯面向对象的语言,所有代码都必须定义在类中。这使得Java非常适合开发大型应用程序和企业级软件。可移植性:Java的跨平台特性使其可以在不同的操作系统上运行,例如Windows、Linux和Mac OS等。简单易学:Java的语法相对简单,易于学习和使用。它还提供了大量的文档和教程,使初学者能够快速入门。高性能:Java的虚拟机(JVM)可以动态地将Java字节码翻译为本地机器代码,从而提高了程序的性能。安全性:Java提供了强大的安全功能,例如沙箱环境和安全管理器,可以帮助保护应用程序免受恶意代码的攻击。大量的类库:Java拥有丰富的类库,涵盖了各种领域,例如网络编程、图形用户界面、数据库访问等。开放源代码:Java是开源的,任何人都可以查看和修改其源代码,这使得Java社区可以不断改进和扩展其功能。面向对象和面向过程的区别面向对象(Object-Oriented,简称 OO)和面向过程(Procedural,简称 PO)是两种不同的编程范式。它们的主要区别在于关注点、设计原则和代码组织方式。以下是面向对象和面向过程之间的一些主要区别:关注点:面向对象编程关注数据和行为之间的关系,强调封装、继承和多态性。面向过程编程关注解决问题的方法,强调输入、处理和输出。设计原则:面向对象编程的设计原则包括封装、继承和多态性。封装确保数据和方法在类内部隐藏,外部无法直接访问;继承允许子类从父类继承属性和方法;多态性允许不同类的对象对同一消息作出不同的响应。面向过程编程的设计原则包括模块化、结构化和自顶向下的分解。模块化使得程序更容易理解和维护;结构化编程有助于提高代码的可读性和可维护性;自顶向下的分解将问题分解为更小的、易于管理的部分。代码组织方式:面向对象编程通常使用类和对象来表示实体和关系,通过调用方法实现功能。这种方式使得代码更加模块化、可重用和易于维护。面向过程编程通常使用函数和过程来表示任务,通过调用函数实现功能。这种方式使得代码更加结构化、易于理解和调试。面向对象编程和面向过程编程的主要区别在于关注点、设计原则和代码组织方式。面向对象编程强调数据和行为之间的关系,以及封装、继承和多态性等设计原则;而面向过程编程关注解决问题的方法,以及模块化、结构化和自顶向下的分解等设计原则。在实际开发中,选择合适的编程范式取决于项目需求、团队技能和其他因素八种基本数据类型的大小,以及他们的封装类Java八种基本数据类型的大小如下:byte:8位,取值范围为-128~127short:16位,取值范围为-32768~32767int:32位,取值范围为-2^31~2^31-1long:64位,取值范围为-2^63~2^63-1float:32位,取值范围为1.4E-45~3.4028235E+38double:64位,取值范围为4.9E-324~1.7976931348623157E+308char:16位,Unicode编码,一个字符占用两个字节,取值范围为'\u0000'~'\uffff'Java中对应八种基本数据类型的封装类分别为:Byte:java.lang.ByteShort:java.lang.ShortInteger:java.lang.IntegerLong:java.lang.LongFloat:java.lang.FloatDouble:java.lang.DoubleCharacter:java.lang.CharacterString:java.lang.String// 使用byte类型存储整数 byte b = 10; // b的值为10,占用一个字节(8位) System.out.println("b的值为" + b); // 输出结果为b的值为10 // 使用short类型存储整数 short s = 10; // s的值为10,占用两个字节(16位) System.out.println("s的值为" + s); // 输出结果为s的值为10 // 使用int类型存储整数 int i = 10; // i的值为10,占用四个字节(32位) System.out.println("i的值为" + i); // 输出结果为i的值为10 // 使用long类型存储整数 long l = 10L; // l的值为10,占用八个字节(64位) System.out.println("l的值为" + l); // 输出结果为l的值为10 // 使用float类型存储浮点数 float f = 10F; // f的值为10,占用四个字节(32位),其中小数部分占用了三个字节(24位) System.out.println("f的值为" + f); // 输出结果为f的值为10.000000 // 使用double类型存储浮点数 double d = 10D; // d的值为10,占用八个字节(64位),其中小数部分占用了七个字节(56位) System.out.println("d的值为" + d); // 输出结果为d的值为10.0000000000000000000000000000000000000000000000000​标识符的命名规则Java标识符的命名规则如下:标识符由字母、数字和下划线组成,但是必须以字母或下划线开头。Java中的关键字不能作为标识符的一部分,包括public、private、protected、static、interface、abstract、final、volatile、transient等关键字。标识符只能在类、接口、方法和变量中使用。Java中的保留字(如if、else、for、while等)也不能作为标识符的一部分。public class MyClass { private int myInt; // 整型变量myInt的命名符合Java标识符的命名规则 private String myString = "Hello World"; // 字符串变量myString的命名符合Java标识符的命名规则 public void myMethod() { double myDouble = 3.14; // 双精度浮点型变量myDouble的命名符合Java标识符的命名规则 } }​instanceof 关键字的作用instanceof 是 Java 中的一种关键字,用于检查一个对象是否是某个特定类(或其子类)的实例。它通常与 new 操作符一起使用,以创建一个新对象并检查其类型。public class Animal { public void makeSound() { System.out.println("Animal is making a sound."); } } public class Dog extends Animal { @Override public void makeSound() { System.out.println("Dog is barking."); } } public class Main { public static void main(String[] args) { Animal animal = new Dog(); // 创建一个狗对象 if (animal instanceof Dog) { // 检查动物对象是否是狗的实例 System.out.println("The animal is a dog."); } else if (animal instanceof Animal) { // 检查动物对象是否是任何动物的实例(包括狗和猫等) System.out.println("The animal is an animal."); } else { // 如果不是狗或任何动物的实例,则输出错误信息 System.out.println("The animal is neither a dog nor an animal."); } } }​Java自动装箱与拆箱Java自动装箱与拆箱是Java语言中的一个重要特性,它允许程序员在不需要显式声明类型的情况下将基本数据类型转换为对象类型。以下是Java自动装箱与拆箱的示例代码: 自动装箱 int a = 5; Integer b = a; // 将int类型的a自动装箱成Integer类型 System.out.println(b); // 输出结果为5 自动拆箱 Integer c = new Integer(5); int d = c; // 将Integer类型c自动拆箱成int类型 System.out.println(d); // 输出结果为5 抛出异常 int e = 0; try { int f = (int) "0"; // 将字符串"0"强制转换为int类型,会抛出NumberFormatException异常 } catch (NumberFormatException ex) { System.out.println(ex.getMessage()); // 输出结果为"Value is not a number" } 最大值和最小值检查 int g = Integer.MAX_VALUE; if (g == 10) { System.out.println("g is equal to 10"); // 输出结果为"g is equal to 10" } else { System.out.println("g is not equal to 10"); // 输出结果为"g is not equal to 10"​重载和重写的区别Java中的方法重载(Overloading)和方法重写(Overriding)是面向对象编程中的两个重要概念,它们在功能上有所区别。重载(Overloading): 重载是指在一个类中,方法名相同但参数列表不同的多个方法。编译器根据传递给方法的参数类型和数量来决定调用哪个方法。例如:public class MyClass { public void method(int a, int b) { System.out.println("Method with two integers: " + a + b); } public void method(String str) { System.out.println("Method with a string: " + str); } }​在这个例子中,我们定义了两个名为method的方法,它们具有相同的名称,但参数列表不同。当我们使用这两个方法时,编译器会根据传递给它的参数类型和数量自动选择合适的方法。重写(Overriding): 重写是指子类重新定义与父类同名、同参数列表和返回类型的方法。当子类重写一个父类的方法时,子类的方法将覆盖父类的方法。class Animal { public void eat() { System.out.println("Animal is eating"); } } class Dog extends Animal { @Override public void eat() { System.out.println("Dog is eating"); } } ​在这个例子中,我们定义了一个名为eat的方法,它是一个抽象方法,表示动物吃东西的行为。然后我们创建了一个名为Dog的子类,并重写了eat方法。当我们创建一个Dog对象并调用eat方法时,输出结果将是"Dog is eating",而不是"Animal is eating"。这是因为子类重写了父类的方法​​equals与==的区别Java中的equals()和==都是用于比较两个对象是否相等的方法,但它们之间有一些细微的差别。equals()方法是Object类中的方法,而==运算符是基本类型(如int、float等)的方法。因此,如果要比较一个自定义对象与另一个自定义对象,应该使用equals()方法而不是==运算符。equals()方法比较的是两个对象的内容是否相等,包括数据类型和值。而==运算符比较的是两个对象的引用是否相等,即它们是否指向同一个内存地址。​public class Person { private String name; private int age; // 构造函数 public Person(String name, int age) { this.name = name; this.age = age; } // equals方法 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name); } // toString方法 @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }在上面的代码中,我们定义了一个Person类,它有两个属性:name和age。我们在类中重写了equals()方法和toString()方法。在equals()方法中,我们首先判断两个对象是否为同一个对象,如果是则返回true,否则通过getClass()方法获取两个对象的类类型并进行比较,最后再比较两个对象的属性值是否相等。在toString()方法中,我们只是简单地将属性值拼接成字符串输出。Hashcode的作用Hashcode是Java中用于比较两个对象是否相等的方法。它的作用是返回一个整数,表示当前对象的哈希码值。如果两个对象的哈希码值相同,则说明它们在内存中的地址相同,即相等。public class HashCodeExample { public static void main(String[] args) { String str1 = "Hello"; String str2 = "World"; int hash1 = str1.hashCode(); // 计算str1的哈希码值 int hash2 = str2.hashCode(); // 计算str2的哈希码值 System.out.println("str1的哈希码值为:" + hash1); System.out.println("str2的哈希码值为:" + hash2); if (hash1 == hash2) { // 判断两个字符串的哈希码值是否相等 System.out.println("str1和str2相等"); } else { System.out.println("str1和str2不相等"); } } } str1的哈希码值为:504839640 str2的哈希码值为:720774163 str1和str2不相等​​String、String StringBuffffer 和 StringBuilder 的区别是什么?Java中的String、StringBuffer和StringBuilder都是用于处理字符串的类,但它们之间存在一些关键区别。以下是关于这三个类的详细说明:String:String类是Java中最常用的字符串类,它表示一个不可变(immutable)的字符序列。当你创建一个String对象时,Java会在堆内存中分配一块连续的空间来存储这个字符串。这意味着一旦你创建了一个String对象,你就无法更改其内容。String str1 = "Hello, world!"; System.out.println(str1); // 输出: Hello, world!​StringBuffer:StringBuffer类是一个可变的字符串缓冲区,允许你在运行时修改字符串。当你创建一个StringBuffer对象时,Java会分配一块动态增长的内存空间来存储这个字符串。这意味着你可以在程序运行过程中随时修改字符串的内容。StringBuffer strBuffer = new StringBuffer("Hello, Java!"); strBuffer.append(", World!"); // 修改字符串内容 System.out.println(strBuffer); // 输出: Hello, Java!, World!StringBuilder:StringBuilder类也是一个可变的字符串缓冲区,但它的行为与StringBuffer类似,但性能更好。当你创建一个StringBuilder对象时,Java同样会分配一块动态增长的内存空间来存储这个字符串。然而,由于它的内部实现方式不同,它在修改字符串时的速度通常比StringBuffer快。StringBuilder stringBuilder = new StringBuilder("Hello, Java!"); stringBuilder.append(", World!"); // 修改字符串内容 System.out.println(stringBuilder); // 输出: Hello, Java!, World!如果你需要在程序运行过程中频繁地修改字符串,那么使用StringBuilder或StringBuffer可能更合适。而如果你只需要创建一个不可变的字符串常量,那么使用String就足够了。​​ArrayList和linkedList的区别ArrayList和LinkedList都是Java中常用的集合类,它们的主要区别在于内部实现和性能。内部实现:ArrayList是基于数组(Array)实现的,而LinkedList是基于链表(Linked List)实现的。因此,对于对元素的随机访问,ArrayList比LinkedList更快;而对于插入、删除操作,LinkedList比ArrayList更高效。性能:由于ArrayList是基于数组实现的,它在随机访问方面表现非常优秀,但是在插入、删除元素时需要移动后面的元素,所以时间复杂度为O(n),其中n为元素数量。而LinkedList是基于链表实现的,插入、删除元素的时间复杂度为O(1),但是随机访问元素需要遍历整个链表,所以时间复杂度为O(n)。import java.util.ArrayList; import java.util.LinkedList; import java.util.Random; public class ArrayListExample { public static void main(String[] args) { // 创建ArrayList对象 ArrayList<Integer> list1 = new ArrayList<>(); list1.add(1); list1.add(2); list1.add(3); list1.add(4); list1.add(5); System.out.println("ArrayList: " + list1); // 创建LinkedList对象 LinkedList<Integer> list2 = new LinkedList<>(); list2.add(1); list2.add(2); list2.add(3); list2.add(4); list2.add(5); System.out.println("LinkedList: " + list2); // 添加元素到ArrayList中 Random random = new Random(); for (int i = 0; i < 10; i++) { int num = random.nextInt(10); if (list1.contains(num)) { continue; } else { list1.add(num); } } System.out.println("ArrayList: " + list1); // 添加元素到LinkedList中 for (int i = 0; i < 10; i++) { int num = random.nextInt(10); if (list2.contains(num)) { continue; } else { list2.add(num); } } System.out.println("LinkedList: " + list2); } }HashMap和HashTable的区别Java中的HashMap和HashTable都是用于存储键值对的数据结构,但它们之间有一些重要的区别。线程安全性:HashTable是线程安全的,而HashMap是非线程安全的。这意味着在多线程环境下使用HashMap时需要进行同步处理,否则可能会出现数据不一致的情况。性能:HashMap通常比HashTable更快,因为HashMap内部使用哈希表来实现,而HashTable则是基于数组实现的。Null值:HashMap允许Key和Value为null,而HashTable不允许。初始容量和增长因子:HashMap有固定的初始容量和增长因子,而HashTable没有。HashMap的初始容量为16,增长因子为0.75;而HashTable的初始容量为11,增长因子为0.75。​import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; public class MapExample { public static void main(String[] args) { // 创建HashMap对象 HashMap<Integer, String> map1 = new HashMap<>(); map1.put(1, "one"); map1.put(2, "two"); map1.put(3, "three"); System.out.println("HashMap: " + map1); // 创建HashTable对象 HashSet<Integer> set1 = new HashSet<>(); set1.add(1); set1.add(2); set1.add(3); System.out.println("HashTable: " + set1); } }​Collection包结构,与Collections的区别Java Collection包是Java集合框架的核心,它提供了一组接口和类来处理集合。Java Collection包结构包括以下几个部分:接口Java Collection包中定义了许多接口,例如List、Set、Map等。这些接口定义了集合的基本操作,例如添加元素、删除元素、查找元素等。类Java Collection包中定义了许多类,用于实现各种接口。例如,ArrayList类实现了List接口,LinkedList类实现了List接口并保持元素的插入顺序,HashMap类实现了Map接口,TreeMap类实现了Map接口并按照自然排序或自定义排序方式对键进行排序等。静态方法Java Collection包中还定义了一些静态方法,用于创建新的集合对象或对现有集合进行操作。例如,Collections.singletonList()方法可以创建一个只包含一个元素的List集合,Collections.emptyList()方法可以创建一个空的List集合,Collections.unmodifiableList(List list)方法可以将一个List集合转换为不可修改的集合等。import java.util.ArrayList; import java.util.List; public class Example { public static void main(String[] args) { // 创建一个List集合对象 List<String> list = new ArrayList<>(); list.add("apple"); list.add("banana"); list.add("orange"); // 输出List集合中的元素数量 System.out.println("List集合中的元素数量:" + list.size()); // 将List集合转换为字符串并输出 System.out.println("List集合转换为字符串:" + list); } }java 的四种引用,强软弱虚Java中四种引用是:Strong Reference(强引用):是指在程序中直接使用一个对象时所使用的引用,如果该对象没有其他强引用指向它,那么它会被垃圾回收器回收。Soft Reference(软引用):是指在程序中使用一个弱引用来引用一个对象,只有在内存不足时才会被回收。Weak Reference(弱引用):是指在程序中使用一个虚引用来引用一个对象,只要任何地方有一个强引用指向它,它就不会被回收。Final Reference(最终引用):是指在程序中使用一个永久引用来引用一个对象,无论何时何地,只要存在这个引用,对象就不会被回收。// 创建一个对象并使用Strong Reference引用它 Object obj = new Object(); ReferenceType objRef = new ReferenceType(obj); System.out.println("obj的值为:" + obj.toString()); System.out.println("objRef的值为:" + objRef.get()); // 将objRef设置为null,表示不再使用Strong Reference引用它 objRef = null; System.gc(); // 执行一次垃圾回收 System.out.println("obj的值为:" + obj.toString());​泛型常用特点Java泛型是Java编程语言的一个重要特性,它允许程序员在编译时为数据类型指定通用类型参数。以下是Java泛型的一些常用特点:类型安全:泛型可以确保在运行时不会发生类型不匹配的问题,从而提高程序的稳定性和安全性。代码重用:通过使用泛型,程序员可以将相同的代码用于不同类型的数据结构,从而提高代码的复用性。类型擦除:Java泛型实现了类型擦除,这意味着在运行时,实际使用的是原始类型,而不是泛型类型。这有助于减少内存开销,提高性能。public class GenericClass<T> { private T value; public void setValue(T value) { this.value = value; } public T getValue() { return value; } } public class Main { public static void main(String[] args) { GenericClass<Integer> integerClass = new GenericClass<>(); integerClass.setValue(10); System.out.println("Value of integerClass: " + integerClass.getValue()); // Output: Value of integerClass: 10 GenericClass<String> stringClass = new GenericClass<>(); stringClass.setValue("Hello, World!"); System.out.println("Value of stringClass: " + stringClass.getValue()); // Output: Value of stringClass: Hello, World! } } 我们定义了一个名为GenericClass的类,它具有一个泛型类型参数T。然后我们创建了两个不同的GenericClass实例:integerClass和stringClass,它们分别使用了整数和字符串作为泛型类型参数Java创建对象有三种方式:使用new关键字创建对象 java复制代码Person person = new Person("张三", 20);使用反射机制创建对象 java复制代码Class<?> clazz = Class.forName("com.example.Person"); Object obj = clazz.newInstance();使用工厂模式创建对象 java复制代码// 定义一个工厂类,用于创建Person对象 public class PersonFactory { public static Person createPerson(String name, int age) { Person person = new Person(name, age); return person; } } // 在其他地方调用工厂类创建Person对象 Person person = PersonFactory.createPerson("张三", 20);​有没有可能两个不相等的对象有相同的hashcode在Java中,如果两个对象的hashCode()方法没有正确实现,那么它们可能会有相同的hashCode值。这是因为hashCode()方法的目的是生成一个整数,用于标识对象在哈希表中的位置,而哈希表使用的是散列算法(如MD5或SHA-1),这些算法并不要求不同的对象具有不同的哈希码值。 java复制代码 public class UnequalHashCodeExample { public static void main(String[] args) { String str1 = "Hello"; String str2 = "World"; int hashCode1 = str1.hashCode(); int hashCode2 = str2.hashCode(); System.out.println("str1 hash code: " + hashCode1); System.out.println("str2 hash code: " + hashCode2); if (hashCode1 == hashCode2) { System.out.println("The two strings have the same hash code!"); } else { System.out.println("The two strings do not have the same hash code!"); } } }在这个例子中,我们创建了两个字符串对象:str1和str2,它们的内容分别为"Hello"和"World"。然后,我们分别调用它们的hashCode()方法并打印结果。由于这两个字符串的内容不同,我们期望它们的哈希码也不同。然而,当我们运行这段代码时,我们会发现它们确实具有相同的哈希码值(输出结果为:"The two strings have the same hash code!"),这说明在某些情况下,两个不相等的对象确实可能具有相同的哈希码。深拷贝和浅拷贝的区别是什么?Java中的深拷贝和浅拷贝都是对象复制的方式,它们的区别在于是否对原始对象及其引用类型进行递归复制。浅拷贝(Shallow Copy): 浅拷贝只复制对象本身及其基本类型属性(如int、float等),而不复制引用类型属性(如String、List等)所指向的对象。换句话说,浅拷贝会创建一个新的对象,但是新对象的引用类型属性仍然指向原始对象。这意味着在原始对象中修改引用类型属性时,新对象的引用类型属性也会受到影响。 public class ShallowCopyExample { public static void main(String[] args) { List<Integer> originalList = new ArrayList<>(Arrays.asList(1, 2, 3)); List<Integer> shallowCopyList = new ArrayList<>(originalList); // 浅拷贝 originalList.add(4); // 在原始列表中添加元素4 System.out.println("Original list: " + originalList); // [1, 2, 3, 4] System.out.println("Shallow copy list: " + shallowCopyList); // [1, 2, 3, 4] } }深拷贝(Deep Copy): 深拷贝会递归地复制原始对象及其引用类型属性所指向的对象。这意味着在原始对象中修改引用类型属性时,新对象的引用类型属性不会受到影响。​import java.util.ArrayList; import java.util.List; public class DeepCopyExample { public static void main(String[] args) { List<Integer> originalList = new ArrayList<>(Arrays.asList(1, 2, 3)); List<Integer> deepCopyList = new ArrayList<>(originalList); // 深拷贝 originalList.add(4); // 在原始列表中添加元素4 System.out.println("Original list: " + originalList); // [1, 2, 3, 4] System.out.println("Deep copy list: " + deepCopyList); // [1, 2, 3, 4] } }​
  • [问题求助] 预置安装成功,进入网页DV安装失败,需要看哪些日志?
    预置安装成功,进入网页DV安装失败,需要看哪些日志?
  • [技术干货] asp取整数mod 有小数的就自动加1
    有一位同学问我一个问题:asp程序,有一个不确定的数除以10,结果需要用asp程序处理取整数,如果有小数点就自动加1这个问题有两个解决思路,如果用在分页上,rs的属性pagecount就可以轻松实现,另外一种方法是数学判断方法。现在做分别介绍。除法分页方法rs.pagesize = 10这个代表每页10条记录response.write(rs.pagecount)这个代表直接输出一共有多少页利用这种方法,如果总记录数除以10有余数,那么结果就会自动加一。数学判断法12345678<%dim a,bif a mod 10 <>0 thenb = a/10 + 1elseb= a/10end if%>第二种方法是a除以10,如果余数不等于0,那么结果就加1。通过这种方法,也可实现要的功能。asp mod运算函数Mod()功能:取余数.mod函数是一个求余函数,其格式为: mod(nExp1,nExp2),即是两个数值表达式作除法运算后的余数。那么:两个同号整数求余与所知的两个正数求余完全一样(即两个负整数与两个正整数的算法一样),即两数取余后返回两数相除的余数。  ASP是动态服务器页面(Active Server Page)的英文缩写。是微软公司开发的代替CGI脚本程序的一种应用,它可以与数据库和其它程序进行交互,是一种简单、方便的编程工具。ASP的网页文件的格式是 .asp。现在常用于各种动态网站中。VBScript中 mod函数是取余除法是 /整除是 \Mod 运算符两个数值相除并返回其余数。result = number1 Mod number2例子:3 Mod 2 结果:1
  • [技术干货] ASP实现SQL备份、恢复
    1、备份<%SQL="backup database 数据库名 to disk='"&Server.MapPath("backup")&"\\"&"backuptext.dat"&"'"set cnn=Server.createobject("adodb.connection")cnn.open "driver={SQL Server};Server=服务器名;uid=sa;pwd="cnn.execute SQLon error resume nextif err<>0 thenresponse.write "错误:"&err.Descriptingelseresponse.write "数据备份成功!"end if%>绿色c hinaip ower. comAYrCJ6B2、恢复<%SQL="Restore database 数据库名 from disk='"&Server.MapPath("backup")&"\\"&"backuptext.dat"&"'"set cnn=Server.createobject("adodb.connection")cnn.open "driver={SQL Server};Server=服务器名;uid=sa;pwd="cnn.execute SQLon error resume nextif err<>0 thenresponse.write "错误:"&err.Descriptingelseresponse.write "数据恢复成功!"end if%>
  • [技术干货] asp判断某个文件是否存在的函数
    最近在写功能的时候需要判断某个文件是否存在,存在则调用,不存在则动态显示页面的功能,用到了下面的代码,特分享一下需要的朋友可以参考一下。两个函数都是基于ASP中的FileSystemObject对象,也就是FSO,写成函数方便以后使用。ASP检查目录是否存在的函数代码12345Function isExistFolder(Byval folderDir)    on error resume next    If objFso.FolderExists(server.MapPath(folderDir)) Then isExistFolder=True Else isExistFolder=False    if err then err.clear:isExistFolder=FalseEnd FunctionASP检查文件是否存在的函数代码12345Function isExistFile(Byval fileDir)    on error resume next    If (objFso.FileExists(server.MapPath(fileDir))) Then isExistFile=True Else isExistFile=False    if err then err.clear:isExistFile=FalseEnd Functionasp中判断文件是否存在(不是本机上的文件)用fso.fileexists只能查询本地文件是否存在,用组件xmlhttp的readyState的方法可以获取远程文件是否存在,返回大于0,表示文件存在,否则,就是不存在。123456set XMLHTTP =Server.CreateObject("Microsoft.XMLHTTP")XMLHTTP.open("HEAD","http://www.test.com/test.htm",false)XMLHTTP.send()if XMLHTTP.status=200 then'文件存在end ifASP判断文件是否存在以及删除文件实例代码1234567891011<%'ASP判断文件是否存在以及删除文件实例代码dim htmlFilefshtmlFile="../book_show.html"htmlFile=server.MapPath(htmlFile)      Set fs=Server.CreateObject("Scripting.FileSystemObject")If fs.FileExists(htmlFile) Then '判断文件是否存在   fs.DeleteFile htmlFile,true '如果文件存在,则删除文件end ifSet fs=Nothing%>
  • [技术干货] asp限制域名访问实现代码
    asp 设置只能指定域名可以使用此网站代码一 脚本之家原创12345678910<% myIp = ",127.0.0.1,localhost,www.jb51.net,"myurl= request.ServerVariables("SERVER_NAME")Response.write myurlif InStr(myIp,","&myurl&",")>0 thenResponse.write "域名合法"elseResponse.write "域名不合法"end if%>代码二123456789101112131415myIp = Array("127.0.0.1","jb51")myHou = new Array("",".com")myDirect ="//www.jb51.net/"ip= request.ServerVariables("HTTP_HOST")j=0for i=0 to ubound(myIp)'Response.Write(i&"--"&myIp(i)&"<br>")if InStr(ip,myIp(i)&myHou(i))>0 then'Response.Write(myIp(i)&"==")j=j+1end ifnextif j<1 thenresponse.Redirect(myDirect)end if上面的代码用到了下面的资料asp获取当前域名和端口号方法asp获取当前域名从来就不是什么有难度的事情,但是在实际项目使用中,大家获取的具体URL信息可能是不同的,各个方法获取见下表,而如果要获取当前域名,可以看下面加粗部分:Request.ServerVariables("SERVER_NAME")'当前域名Request.ServerVariables("SERVER_PORT")'当前端口Request.ServerVariables("SCRIPT_NAME")'当前文件名Request.ServerVariables("QUERY_STRING")'当前页面的传入参数Request.ServerVariables("HTTP_USER_AGENT")'取得当前浏览器信息Request("remote_addr")'取得IPRequest.ServerVariables("HTTP_REFERER")'上个页面地址Request.ServerVariables("HTTP_HOST")'获取当前域名当采用SERVER_NAME时返回的是不带端口号的URL
  • [活动打卡] Day1ASP.NET Core 基础
    .net core 开源跨平台,集成当前各种流行的技术框架;.net 6为长期支持版本,.net core 2/3即将关闭支持;中间模式是非常优秀的设计和特色,next(),可无限的加中间处理过程;模块化是非常好的设计;适合各类网页、iot、桌面、app的运用开发,适合云原生的开发;云原生开发是一个庞大的开发体系,并不是单单的某个开发语言或环境;devops是个大趋势;
  • 云享读书会《深入浅出ASP.NET Core》
    https://developer.huaweicloud.com/signup/2e4da6016dac4fb18d20e05fa0fd72bc 有邀请活动
  • [获奖公告] 【奖品已于7月22日邮寄】【云享读书会第11期】《深入浅出ASP.NET Core》读书笔记征集,更有礼品相送~
    开始活动前,请先报名本期读书会https://developer.huaweicloud.com/activity/reading_11.html--------------------------------------------------------------开发者,你好哟~华为云 · 云享读书会 第11期 它来了 !本期领读书籍为《深入浅出ASP.NET Core》由领读书籍原作者、华为云MVP、微软MVP、华为云云享专家、Microsoft Tech Summit 讲师、52ABP框架作者——梁桐铭老师,带你精读这本深入浅出ASP.NET Core!经过老师的视频领读,如果你有相关知识收获,欢迎在此帖留下你的读书笔记~获奖信息公示(公示期截止7月5日)最佳读书笔记奖励张辉花溪孙小北积分排名1~5名昵称Day1Day2Day3Day4Day5测试题1测试题2测试题3测试题4测试题5互动答疑总成绩孙小北 100100100100100100100100100100601060RabbitCloud100100100100100100100100100100601060allen2000100100100100100100100100100100601060zekelove100100100100100100100100100100601060夏暖100100100100100100100100100100601060积分排名6~15名张辉100100100100100100100100100100201020禄仁恝100100100100100100100100100100201020iolink1002100100100100100100100100100100201020仲劲100100100100100100100100100100201020AAAI100100100100100100100100100100201020HB168810010010010010010010010010075401015云水不言10010010010010010010010010010001000花溪10010010010010010010010010010001000Ethins10010010010010010010010010010001000yjh879238 10010010010010010010010010010001000恭喜以上开发者获得活动奖励,请点击下方链接填写获奖信息,请于7月20日前完成填写,过期视为弃奖哦~如有任何疑问可以和小助手联系~https://devcloud.huaweicloud.com/expert/open-assessment/qtn?id=3d3d196636fc4df9874cd247e36418bd&utm_source=ASPNetCore征集时间2021.06.15 - 2021.06.27读书笔记要求1. 每篇读书笔记字数要求≥300字;2. 内容要求与每日领读视频、领读书籍或是其他.NET Core技术领域相关;3. 内容原创不可抄袭;4. 回帖时请务必留下你的微信昵称和华为云账号。03. 注意事项1. 读书笔记提交后,小助手会在3个工作日内按续完成审核,并增加活动积分100活动积分/篇;2. 本次活动通过提交读书笔记,可获得的积分上限为500分;3. 请务必按照上述要求提交内容,以免影响积分增加;4. 若积分值相同则以完成学习任务的时间先后排序,其中任务完成时间的判定优先级为:读书笔记>自测题>专家Q&A>其他;5. 其他积分获取方式请查看活动社群公告;6. 其他未说明事项请参照 云享读书会《深入浅出ASP.NET Core》04. 最佳读书笔记奖励针对活动时间内提交的有效读书笔记,领读专家将根据内容质量和完成篇数综合评选3位最佳读书笔记获奖者,并奖励提交人荣耀猎人路由器1个05. 活动排行奖励最终积分排名1~5名     最终积分排名6~15名06. 关于云享读书会每期云享读书会活动,会选取一本技术相关的畅销书籍,由原作者/行业专家提炼书籍精华,在读书会的专属微信社群中,每日输出精华知识的领读视频,帮助大家快速积累专业知识。活动期间会设置每日自测题、结业实践任务、提交读书笔记三种积分获取任务,并根据活动结束后的积分排行发放活动奖励。07. 加入学习社群然后添加小助手微信,备注“NET Core”加入学习社群。
  • 快速开发调试您的 ASP 接口
    重新定义了 ASP 开发模式特色:1、快速搭建、开发 API 接口,数据格式采用目前最流行的 json 传输。2、接口页即文档页,并可实时输入参数调试运行,调试接口再也无需等待前端程序员完成页面重构。3、封装了部分微信接口。4、封装了数据库操作类,同时支持 SQL Server + SQL Server Lite (SQL CE) 两种数据库,使用传参方式,杜绝 SQL 注入。5、实现了用户身份绑定、限时缓存更新等常用功能。 
  • [技术干货] Jexus 网站服务器和 ASP.NET 跨平台开发
    Mono 和 Jexus 网站服务器Mono 这个开源项目其实一直伴随着 .NET Framework 成长。Miguel de Icaza 先生早年一直领导者 Gnome 这个开源桌面系统的开发。在2000年微软公布了 C# 语言和 .NET Framework 之后,他非常感兴趣并且希望能把这些新技术带到 Linux 平台,于是一手建立了 Mono 这个项目和社区。现在 Mono 的稳定版本是 6.10,全面兼容.NET 5,是.NET 5统一框架下的2大运行时之一,相对于.NET Framework停留在4.8 版本,Mono一直在进化,在移动开发Xamain、前端Blazor具有一席之地,同时在服务器段也是.NET Core 有益补充。和 .NET Core  另起炉灶相比,Mono 处处都保持着和 .NET Framework 的兼容性。在微软2014年11月完全基于 MIT 协议开放 .NET Framework 参考代码后,Mono 立即开始集成微软的代码 ,非常明显的改善了兼容性。不过 Mono 保持了自己独立开发的 CLR 实现和 C# 编译器,有自己的 AOT 运行环境和 C# Shell。在应用程序框架方面,Mono 提供 WinForms 和 WebForms 支持,也包含了微软早已开源的 MVC 5、Web API 2 和 SignalR 2。在 Mono 这个稳固的基础之上,中国四川的一位微软 C# MVP 刘冰历时多年设计了一款免费的网站服务器,取名 Jexus,最新稳定版本是6.2。作为一款跨平台软件,它支持各种主流 Linux 发布版本和 FreeBSD,特别是国内应用创新领域对于华为的鲲鹏(ARM )和龙芯(MIPS/LoongArch)。从架构等技术特点来看,Jexus 也可以媲美 IIS 等商用服务器。比如它提供了多站点支持,拥有应用程序池来调度管理工作进程,具有良好的稳定性和容错能力。又比如它支持 HTTPS 和 WebSockets,支持 FastCGI 协议和 OWIN 标准。它不仅可以作为一款应用服务器,来托管各种 ASP.NET 4 应用(WebForms、MVC、Web API、SignalR),同样也可以作为一般服务器使用,包含 URL 重写、反向代理、压缩传输等基础功能和 SQL 注入预防等多项内置安全防护。Jexus for linux 有如下特点:支持多种操作系统:Jexus最初的设计目标是“跨平台的ASP.NET WEB服务器”,由于在Windows系统上,IIS已经是ASP.NET的优秀平台,所以,当前的Jexus以支持Linux和FreeBSD等非Windows系统为主要设计目标。正因为这个原因,就Linux/FreeBSD等平台的ASP.NET建设而言,Jexus具有特别重大的意义。高性能:“高性能”是Jexus的重要的设计目标。虽然Jexus基于Mono环境运行,但Jexus并非全部由Mono的.NET组件构成,对于涉及性能的关键代码,Jexus非常巧妙地大量采用了Linux/Unix本身的优秀特性,从代码层保证了Jexus的性能优势。同时,Jexus的框架特征也为高性能提供了基础保证。Jexus不象XSP那样,纯HTML也需要经过ASP.NET处理,更不象Apache和Nginx等服务器,需要通过插件的形式间接地对ASP.NET进行支持,Jexus把HMTL静态文件处理模块、ASP.NET处理模块、静态文件高速缓存机制、epoll/poll数据传输机制等进行了高度集成,从架构本身入手,最大限度地提高WEB服务器的处理能力和传输速度。安全性:Jexus内核含有安全监控机制,绝大多数恶意访问在进入网站前就会被Jexus直接禁止,这是Jexus有别于其它WEB服务器的又一大特色,所以,Jexus特别适合那些对安全要求较高的企业网站或政府网站使用。稳定性:从运行机制而言,Jexus系统中,有专门检测工作进程执行状态的管理单元,任何一个进程退出或者任何一个ASP.NET网站应用程序域退出,被会被管理单元发现并得到重启,从而保证了Jexus能够7*24小时不间断工作;从程序本身而言,Jexus程序代码力求简洁,BUG很少,同时,Jexus的每个版本在正式发布之前,都要经过严格的压力测试,影响稳定性的因素,几乎在正式发布之前即已被全部排除。功能强大:Jexus支持URL重写,支持多目标服务器的反向代理,支持PHP,支持GZIP压缩传输,并且,可以利用不同端口、不同虚拟路径、不同域名设置任意数量的网站,这些功能要素,表明了Jexus是一款功能完整而强劲的WEB服务器。安装、配置、操作极为简单,服务社区化,各种问题能得到快速的处理,有良好的后续服务支撑能力。总体上来说,jexus除其它通用服务器应用的静态处理与反向代理功能外,另外三个特色比较突出:一,真正纯国产;二,入侵检测;三,支持asp.net/core。鲲鹏(ARM)上部署 Jexus 有两种安装方式:1是使用官方自动安装脚本:curl https://jexus.org/release/arm64/install.sh|sudo sh安装完成的目录地址为/usr/jexus 2是使用手动安装,可以自定义目录,我们这里也安装到/usr/lexus/目录下方便理解      wget https://linuxdot.net/down/jexus-6.2.x-arm64.tar.gz      tar zxvf jexus-6.2.x-x64.tar.gz Jexus的配置文件cd siteconf/                    #进入配置文件目录vim web                   #新建一个配置文件名为web,并进行编辑####################### Web Site: web ########################################                                                                                port=80                        # 监听端口:使用域名的话为80root=/ /var/www/default        # 运行目录 .NetCore web项目需要把项目目录指向到wwwroot目录,不支持虚拟目录hosts=web.test.com            # 服务器绑定域名,在hosts做一个本地域名也可以,也可以是IP地址,这里就不做演示了# User=www-data# AspNet.Workers=2  # Set the number of asp.net worker processes. Defauit is 1.# addr=0.0.0.0# CheckQuery=false# NoLog=true                                                                                                AppHost={                        # 新建AppHost配置  cmd=/var/wwww/deault/myWeb;     # 进行dotnet 项目名.dll运行操作  root=/var/wwww/deault;              # 项目的工作目录  # port=5001                     # 可选项。表示这个应用程序的侦听端口,多个端口用英文逗号分隔  #OutLog=/log/out.txt;                 # OutLog:可选项。表示将这个应用程序的控制台输出重定向到指定的文件(需填写完整路径);  #ErrLog=/log/out.txt;                         # ErrLog:可选项。表示将这个应用程序的异常输出重定向到指定的文件(需填写完整路径),如果不原意输出日志,可以不用OutLog项。这时, jexus会自动关掉控制台输出  }确保配置和项目文件无误后,进入目录运行jexuscd /usr/jexussudo ./jws start ... OK.使用浏览器测试一下:设置开机启动新建 jexus.servicecd /lib/systemd/systemvi jexus.service添加如下配置[Unit]Description=jexusAfter=network.target[Service]Type=forkingExecStart=/usr/jexus/jws startExecReload=/usr/jexus/jws restartExecStop=/usr/jexus/jws stopPrivateTmp=true[Install]WantedBy=multi-user.targetjexus加入服务: systemctl enable jexus.service启动jexus服务: systemctl start jexus.service查看jexus服务状态: systemctl status jexus.service
  • [技术干货] ASP.NET Core服务器综述
    ASP.NET Core应用通过一个进程内的HTTP服务器实例实现运行,这个服务器实例侦听HTTP请求并将请求作为组成HttpContext的一组请求功能集暴露给我们的应用程序。ASP.NET Core搭载两个服务器实现:Kestrel是一个基于libuv的跨平台HTTP服务器,libuv是一个跨平台的异步I/O库WebListener是一个基于HTTP.SYS内核驱动的“Windows专用”HTTP服务器KestrelKestrel是包含在ASP.NET Core新项目模板中默认的web服务器。如果你的应用只接收来自内部网络的请求,你可以只使用Kestrel本身。如果你将你的应用部署在公共网络上,我们建议你使用IIS,Nginx或者Apache作为反向代理服务器。一个反向代理服务器接收来自网络的HTTP请求并且在经过一些初步处理后将请求传递到Kestrel服务器。过程如下图所示。对edge deployments(从公共网络上接触到流量的部署方式)使用反向代理最重要的一个原因就是安全性。因为Kestrel相对较新,对抵御安全攻击至今还没有一个完整的功能补充。安全性处理包括但不限于适当的超时,大小的限制,以及并发连接限制等问题。有关何时使用Kestrel与反向代理的更多信息,请参见Kestrel。IIS with Kestrel当你使用IIS或者IIS Express作为对ASP.NET Core的反向代理时,ASP.NET Core应用将运行在由该IIS工作进程分离出的一个进程中。在该IIS进程中,存在着一个特殊的IIS模块,它被用来协调反向代理的关系。它就是ASP.NET Core模块。ASP.NET Core模块的主要功能包括启动ASP.NET Core应用,当应用崩溃时处理重启,向应用传送HTTP流量。更多的信息,请参考ASP.NET Core Module。Nginx with Kestrel有关如何在Linux使用Nginx作为对Kestrel的反向代理服务器的更多信息,请参考Publish to a Linux Production Environment。Apache with Kestrel有关如何在Linux使用Apache作为对Kestrel的反向代理服务器的更多信息,请参考Using Apache Web Server as a reverse proxy。Jexus with Kestrel有关如何在Linux使用Jexus作为对Kestrel的转发服务器的更多信息,请参考 Jexus 5.8.2 正式发布为Asp.Net Core进入生产环境提供平台支持WebListener如果你在Windows上运行你的ASP.NET Core应用,你可以会遇到以下场景——你既想要在公共网络上部署你的应用,又不能使用IIS,这时,WebListener会是一个可供替代的选择。当你只想要在内网中部署你的应用时,WebListener可以被用来代替Kestrel,特别是当你需要Weblistener服务器支持功能中的某项而Kestrel恰好不支持的时候。对于内部网络场景,为了能达到最好的性能表现,我们通常推荐Kestrel服务器,但是在另一些场景中,你可以想要使用某项仅WebListener支持的功能。关于WebListener功能的更多信息,请参考WebListener。ASP.NET Core 服务器基础组件说明IApplicationBuilder在Startup类中的Configure方法暴露了IFeatureCollection类的ServerFeatures属性。Kestrel和WebListener服务器都只提供了一个单一的功能,IServerAddressesFeature,但是不同的服务器实现可能会显示额外的功能。IServerAddressesFeature可以用来找出哪些服务器实例端口在运行时被绑定。ServerFeatures 的注释为“Gets the set of HTTP features the application's server providers”。自定义服务器你可以创建自定义服务器实现以用来替代Kestrel或者WebListener。Open Web Interface for .NET(OWIN) guide 说明了怎么去实现一个Nowin-based IServer。你可以自由地实现你的应用所需的功能接口,但至少必须支持IHttpRequestFeature和IHttpResponseFeature接口。
  • [技术干货] 将传统 ASP.NET 应用迁移到 .NET Core
    现在越来越多的人在谈论. NET Core。诚然,.NET Core 是未来, 但是.NET Framework 仍在支持, 因为大量的应用程序无法在短时间内迁移。.NET Core 和 .NET Framework 就像电动汽车和汽油动力汽车。汽油车是成熟的,你可以毫无任何问题驾驶它,但电动车有它们的优势,并正在取代汽油车。所以,不要误会,你应该从今天开始迁移到. NET Core。我已经迁移了几个运行在完整.NET Framework和IIS上的传统ASP.NET/MVC项目到ASP.NET Core 2.x,可以运行在IIS或非IIS环境下。这篇文章针对的是新接触.NET Core,但有.NET Framework经验的开发人员,帮助他们将现有的应用更平滑的过渡到.NET Core上。1、迁移或重写有时候,我更喜欢用“重写“而不是”迁移“这个词,因为在有些情况下,.NET Core和.NET Framework是完全不同的两个东西。根据我的经验,大部分前端代码可以只做少量修改就直接移植到.NET Core,因为它们的本质毕竟是服务器技术无关的,天生跨平台的技术。至于后端代码,迁移成本取决于它们对Windows及IIS的耦合程度。我理解,有些应用会充分利用Windows 及 IIS 的特性,这样开发者就可以避免自己费力去实现一些功能。这些包括计划任务、注册表、活动目录或Windows服务等。这些并不能够直接迁移,因为.NET Core是跨平台的。对于这些部分,你可能需要考虑从重新设计业务逻辑,想一种可以实现相同功能,但不依赖于Windows 或IIS 组件的方法。对于无法迁移的历史遗留代码,你可能需要考虑重新设计整个应用的架构,将这些功能作为REST API暴露出来,可以使用.NET Framework上的ASP.NET Web API来实现。这样的话,你的ASP.NET Core 应用得以继续使用这些API并继续完成业务功能。即使你的应用使用了WCF服务,甚至更老的 ASMX 服务,也是可以搞的。因为.NET Core目前有WCF客户端可以调用WCF。2、NuGet 包管理请确保你需要使用的NuGet包支持 .NET Core 或 .NET Standard。如果不支持,那么你需要研究有没有可以替换的NuGet包,或者你是否能够自己写代码去实现相同的功能。.NET Standard 意味着这个包可以同时使用在.NET Framework 4.6.1+ 以及.NET Core,这是取代老的 Portable Class Library (PCL)的技术。所以,如果你看到一个包的依赖项里有.NET Standard,这意味着你能够将它安装到你的.NET Core工程中。有部分包,比如NLog有专门的.NET Core版本,比如 NLog.Web.AspNetCore,你应该选择使用这样的版本。你依然可以在.NET Core工程里引用一个.NET Framework的包,但是这会让你的应用只能跑在Windows上,不推荐这么做。我列出了一些热门使用的NuGet 包,它们都已经支持.NET Core:NLog.Web.AspNetCoreNewtonsoft.JsonHtmlAgilityPackRestSharpNUnitDapperAutoMapperMoq对于客户端包,比如 jQuery,请不要使用NuGet 将它们安装到.NET Core工程中,参见本文的 “客户端包管理” 章节。如果你使用 Visual Studio Code 做 .NET Core 开发,请注意,安装NuGet包的命令不是 Install-Package,那是给Visual Studio的 PowerShell host用的,在VSCode里,你需要使用dotnet CLI工具,比如:dotnet add package Newtonsoft.Json参见 https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-add-package3、客户端包管理ASP.NET Core 曾经使用 Bower 去管理客户端包。但在ASP.NET Core 2.1 里,Bower 已经被移除了,因为作者不干了。因此,微软默认使用自家的包管理器 “Library Manager” 也叫 “libman” 去管理前端包。它能够在 Visual Studio 和 Visual Studio Code 中使用,甚至也能用 CLI 在命令行下使用。libman.json 可以直接编辑,也能在UI中更改,都有智能感知支持。我的建议是,如果你的应用不是重客户端的话,使用 libman 去管理前端包,因为其他技术比如NPM 太重量级了。你会希望在你的编译服务器上安装和配置NodeJS以及其他一切东西,仅仅为了拉取一个jQuery 库。更多详情可参见官方文档 https://docs.microsoft.com/en-us/aspnet/core/client-side/libman/?view=aspnetcore-2.14、Html / JavaScript / CSS你可以直接将这些文件复制到.NET Core工程里。但是请确保你已经把文件路径修改正确,比如CSS里的图片文件路径。因为传统ASP.NET / MVC 模板默认使用 “/Content/” 目录,而.NET Core模板使用“/css/”, “/js/”, “/lib/” 等目录,这并不是强制的,只是约定俗成的规范。如果你希望捆绑并压缩CSS 和JS 文件,有许多工具可以办到。我个人喜欢用VS的一款插件,叫做 “Bundler & Minifier” ,你可以从这里获取https://github.com/madskristensen/BundlerMinifier.这款插件可以在开发时生成捆绑及压缩的文件,但非编译或运行时。5、App_Data 文件夹在传统ASP.NET/MVC 应用中,你可以将数据文件保存到一个名为“App_Data”的特殊文件夹中,但这个东西在.NET Core里不复存在了。为了实现类似的功能,你需要自己创建一个名为“App_Data” 的文件夹,但位于“wwwroot”目录之外。然后像这样使用public void Configure(IApplicationBuilder app, IHostingEnvironment env){    // set    string baseDir = env.ContentRootPath;    AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(baseDir, "App_Data"));     // use    var feedDirectoryPath = $"{AppDomain.CurrentDomain.GetData("DataDirectory")}\\feed";}6、自定义 Http Headers在传统ASP.NET里,你可以在Web.Config 里像这样为每个响应都配置自定义的HTTP Header:<httpProtocol>  <customHeaders>    <add name="X-Content-Type-Options" value="nosniff" />  </customHeaders></httpProtocol>而在.NET Core里,如果你希望脱离Windows去部署你的应用,不可以使用Web.config文件。因此,你需要一个三方的 NuGet 包来完成这个功能:NetEscapades.AspNetCore.SecurityHeadersapp.UseSecurityHeaders(new HeaderPolicyCollection()    .AddCustomHeader("X-UA-Compatible", "IE=edge")    .AddCustomHeader("X-Developed-By", "Edi Wang"));详情参考https://github.com/andrewlock/NetEscapades.AspNetCore.SecurityHeaders7、获取客户端IP地址以及 HttpContext在传统ASP.NET 里,我们能够通过 Request.UserHostAddress 来获取客户端IP地址。但这个属性在 ASP.NET Core 2.x 里是不存在的。我们需要通过另一种方式获取HTTP 请求信息。1. 在你的 MVC 控制器里定义一个私有变量private IHttpContextAccessor _accessor;2.  使用构造函数注入初始化它public SomeController(IHttpContextAccessor accessor){    _accessor = accessor;}3. 获取客户端IP地址_accessor.HttpContext.Connection.RemoteIpAddress.ToString()就是如此简单。如果你的 ASP.NET Core 工程是用MVC默认模板创建的,针对HttpContextAcccessor 依赖注入注册应该在Startup.cs 中完成:services.AddHttpContextAccessor();services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();RemoteIpAddress 的类型是 IPAddress 并不是string。它包含 IPv4, IPv6 以及其他信息。这和传统ASP.NET不太一样,对我们更加有用一些。如果你希望在Razor 视图(cshtml) 里使用,只需要用 @inject 指令注入到view中:@inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor使用方法:Client IP: @HttpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString()8、JsonResult默认情况下,ASP.NET Core 会使用 camelCase 序列化 JsonResult ,而传统 ASP.NET MVC 使用的是PascalCase,这会导致依赖Json结果的 JavaScript 代码爆掉。例如以下代码:public IActionResult JsonTest(){    return Json(new { Foo = 1, Goo = true, Koo = "Test" });}它会返回camelCase 的Json给客户端:如果你有大量JavaScript 代码并不能及时改为使用camelCase,你仍然可以配置 ASP.NET Core 向客户端输出 PascalCase 的Jsonpublic void ConfigureServices(IServiceCollection services){    // Add framework services.    services.AddMvc()        .AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());}现在,之前的代码会返回PascalCase 的结果:9、HttpModules 和 HttpHandlers这两者在ASP.NET Core中被替换为了 Middleware。但在迁移之前,你可以考虑使用别的方法,在一个普通ASP.NET Core Controller 中实现这些功能。例如,我的老博客系统里有个名为“opml.axd” 的HttpHandler 作用是向客户端输出一个XML文档,这其实完全可以用 Controller 来实现:public async Task<IActionResult> Index(){    var opmlDataFile = $"{AppDomain.CurrentDomain.GetData(Constants.DataDirectory)}\\opml.xml";    if (!System.IO.File.Exists(opmlDataFile))    {        Logger.LogInformation($"OPML file not found, writing new file on {opmlDataFile}");         await WriteOpmlFileAsync(HttpContext);        if (!System.IO.File.Exists(opmlDataFile))        {            Logger.LogInformation($"OPML file still not found, something just went very very wrong...");            return NotFound();        }    }     string opmlContent = await Utils.ReadTextAsync(opmlDataFile, Encoding.UTF8);    if (opmlContent.Length > 0)    {        return Content(opmlContent, "text/xml");    }     return NotFound();}我也曾经使用HttpHandler 完成Open Search,RSS/Atom等功能,它们也能够被 重写为Controller。对于其他一些不能够被重写为MVC Controller的组件,例如处理特殊拓展名的请求。请参见:https://docs.microsoft.com/en-us/aspnet/core/migration/http-modules?view=aspnetcore-2.110、IIS URL Rewrite你依然可以使用和旧应用里完全一样的配置文件,不管你的 .NET Core 应用是否部署在IIS上。例如,在应用根目录底下创建一个名为"UrlRewrite.xml"的文件,内容如下:<rewrite>  <rules>    <rule name="Redirect Misc Homepage URLs to canonical homepage URL" stopProcessing="false">      <match url="(index|default).(aspx?|htm|s?html|php|pl|jsp|cfm)"/>      <conditions logicalGrouping="MatchAll" trackAllCaptures="false">        <add input="{REQUEST_METHOD}" pattern="GET"/>      </conditions>      <action type="Redirect" url="/"/>    </rule>  </rules></rewrite>注意:你必须把这个文件设置为always copy到输出目录,不然无效!<ItemGroup>  <None Update="UrlRewrite.xml">    <CopyToOutputDirectory>Always</CopyToOutputDirectory>  </None></ItemGroup>打开 Startup.cs,在Configure 方法中添加如下代码:public void Configure(IApplicationBuilder app, IHostingEnvironment env){    ...    using (var urlRewriteStreamReader = File.OpenText("UrlRewrite.xml"))    {        var options = new RewriteOptions().AddIISUrlRewrite(urlRewriteStreamReader);        app.UseRewriter(options);    }    ...}这在我之前的文章中提到过https://edi.wang/post/2018/9/18/prevent-image-hotlink-aspnet-core.更多选项和用法可以参考 https://docs.microsoft.com/en-us/aspnet/core/fundamentals/url-rewriting?view=aspnetcore-2.111、Web.configWeb.config 文件并没有完全消亡。在 In .NET Core 里,一个 web.config 文件仍然用于在IIS环境下部署网站。在这种场景下,Web.config 里的配置仅作用于 IIS,和你的应用代码没有任何关系。可以参考 https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index?view=aspnetcore-2.1#configuration-of-iis-with-webconfig一个典型的IIS下部署ASP.NET Core应用的web.config 文件如下:<?xml version="1.0" encoding="utf-8"?><configuration>  <location path="." inheritInChildApplications="false">    <system.webServer>      <handlers>        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />      </handlers>      <aspNetCore processPath="dotnet" arguments=".\Moonglade.Web.dll" stdoutLogEnabled="false" stdoutLogFile="\\?\%home%\LogFiles\stdout" />    </system.webServer>  </location></configuration>曾经的 AppSettings 节点可迁移到 appsettings.json,在这篇文章中有详解:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.112、Session 和 CookieASP.NET Core 默认没有开启Session支持,你必须手工添加Session 支持。services.AddDistributedMemoryCache();services.AddSession(options =>{    options.IdleTimeout = TimeSpan.FromMinutes(20);    options.Cookie.HttpOnly = true;});以及app.UseSession();设定和获取Session值:HttpContext.Session.SetString("CaptchaCode", result.CaptchaCode);HttpContext.Session.GetString("CaptchaCode");清除值:context.Session.Remove("CaptchaCode");详情参见:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/app-state?view=aspnetcore-2.113、Html.Action我们曾经使用 Html.Action 去调用一个Action ,返回一个Partial View ,然后放在主要的View 中显示,比如layout页。这在Layout页面中的应用非常广泛,比如在一个博客系统中显示分类列表之类的小部件。@Html.Action("GetTreeList", "Category")在ASP.NET Core里,它被替换为了 ViewComponents,参见 https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components一个要注意的地方是Invoke方法只能是 async 签名的:async Task<IViewComponentResult> InvokeAsync()但如果你的代码并不是天生异步的,为了不让编译器警报,你可以加入这行代码:await Task.CompletedTask;14、检查运行环境是 Debug 或 Release在我的老系统里,我使用 HttpContext.Current.IsDebuggingEnabled 去检查当前运行环境是否为Debug,并在标题栏上显示 “(Debug)” 字样。@if (HttpContext.Current.IsDebuggingEnabled){    <text>(Debug)</text>}在 ASP.NET Core 里,我们可以使用新的razor tag helper 去完成这件事<environment include="Development">    (Debug)</environment>在下面的章节里,你会看到更多razor tag helper 的用法。15、新的Razor Tag HelpersTag helper 可以帮助你讲老的HTML helper 简化为更加面向HTML可读的代码,例如一个表单,我们曾经要这样写:转换为 Tag Helpers 的结果是这样的:我个人最喜欢的功能是给JS或CSS文件自动增加版本字符串:<script src="~/js/app/ediblog.app.min.js" asp-append-version="true"></script>它的结果是:<script src="/js/app/ediblog.app.min.js?v=lvNJVuWBoD_RVZwyBT15T_i3_ZuEIaV_w0t7zI_UYxY"></script>新的razor 语法能够兼容以前的 HTML helpers,也就是说,你依然能在ASP.NET Core中毫无问题的使用老的 HTML helpers。如果你的应用迁移时间紧迫,你可以尽管先使用老代码,随后再逐步转换到Tag Helpers。完整的介绍和语法列表,可参见https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro?view=aspnetcore-2.116、Anti-Forgery TokenAnti-forgery token 有一些改进。首先,你能够自定义cookie 以及字段的名字了。services.AddAntiforgery(options =>{    options.Cookie.Name = "X-CSRF-TOKEN-MOONGLADE";    options.FormFieldName = "CSRF-TOKEN-MOONGLADE-FORM";});第二,你再也不需要手工给每一个表单都增加这行代码了:@Html.AntiForgeryToken()如果你使用新的form tag helper,那么anti-forgery 字段会自动在输出到客户端时自动加上。但你依然需要在后台对应的Action上加上 [ValidateAntiForgeryToken] 属性。然而,有另一种自动给每一个POST请求都验证anti-forgery token 的办法。services.AddMvc(options =>options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()));或者你可以单独给一个 Controller 加上这个属性。[Authorize][AutoValidateAntiforgeryToken]public class ManageController : Controller17、对非Controller 使用依赖注入ASP.NET Core 有自带的 DI 框架可以用在 Controller 上。我们可以修改一个Controller 的构造函数去注入它运行所依赖的服务。public class HomeController : Controller{    private readonly IDateTime _dateTime;     public HomeController(IDateTime dateTime)    {        _dateTime = dateTime;    }}但这不意味着自带的DI框架只能用在Controller 上。对于其他类,你可以使用完全一样的DI,例如,我自定义的类,也可以使用构造函数注入:public class CommentService : MoongladeService{    private readonly EmailService _emailService;     public CommentService(MoongladeDbContext context,        ILogger<CommentService> logger,        IOptions<AppSettings> settings,        EmailService emailService) : base(context, logger, settings)    {        _emailService = emailService;    }          // ....}方法是,只要你把自定义的类注册到Startup.cs中的 DI 容器里即可。services.AddTransient<CommentService>();更多ASP.NET Core 依赖注入的使用方法参见 https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/dependency-injection?view=aspnetcore-2.118、API 行为不一致有些来自传统 ASP.NET 的代码可以无错误编译通过,但这不保证运行时能够成功。比如,这段来自ASP.NET (.NET Framework) 的代码在 ASP.NET Core 中会抛出异常:var buffer = new byte[context.Request.Body.Length];context.Request.Body.Read(buffer, 0, buffer.Length);var xml = Encoding.Default.GetString(buffer);它的结果是:System.NotSupportedException: Specified method is not supported.at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestStream.get_Length()在.NET Core里,我们需要用一种不同的方式去实现:var xml = await new StreamReader(context.Request.Body, Encoding.Default).ReadToEndAsync();19、小心GDPR 带来的问题ASP.NET Core 2.1 默认添加了 GDPR 的支持,但也会给我们带来一些问题。关于GDPR可参见 https://docs.microsoft.com/en-us/aspnet/core/security/gdpr?view=aspnetcore-2.1主要问题是,在用户接受GDPR协议之前,Cookie 是不起作用的。你需要检查哪些Cookie是你应用运行所必须的,即时用户没有接受GDPR协议,并且把它们标记为IsEssential这是我博客系统中的一个例子:private void SetPostTrackingCookie(CookieNames cookieName, string id){    var options = new CookieOptions    {        Expires = DateTime.UtcNow.AddDays(1),        SameSite = SameSiteMode.Strict,        Secure = Request.IsHttps,         // Mark as essential to pass GDPR        // https://docs.microsoft.com/en-us/aspnet/core/security/gdpr?view=aspnetcore-2.1        IsEssential = true    };     Response.Cookies.Append(cookieName.ToString(), id, options);}另一个问题是,如果你要使用Session,那么用户必须接受GDPR 策略,否则 Session是不工作的。因为 Session 需要依赖 Cookie 在客户端保存 SessionID 。20、热更新 Views在传统 ASP.NET MVC 中,Views 文件夹默认不会编译到 DLL 文件中,所以我们能够不需要编译整个应用就能更新razor页面。这在不需要更新C#代码的情况下仅修改文字或一些layout修改的场景下非常实用。我有时候也利用这个特性直接向生产环境发布一些修改后的页面。然而,ASP.NET Core 2.1 默认情况下会将我们的 Views 编译到DLL 中以提高性能。因此,你无法在服务器上直接修改一个视图,因为文件夹中根本就不存在 Views,只有一个 *.Views.dll:如果你仍然希望在ASP.NET Core中热更新Views,需要手工修改csproj文件:<PropertyGroup>  <TargetFramework>netcoreapp2.1</TargetFramework>  <RazorCompileOnBuild>false</RazorCompileOnBuild>  <RazorCompileOnPublish>false</RazorCompileOnPublish></PropertyGroup>21、编译版本号自增长在传统 .NET 应用程序里,我们可以修改 “AssemblyInfo.cs” 在每次编译时自动增加版本号。这在编译服务器里十分常用。[assembly: AssemblyVersion("9.0.*")]结果是这样:9.0.6836.29475不幸的是,.NET Core 目前还没有一个自带的方法来完成这个操作。只有一个三方解决方案可能有用:https://github.com/BalassaMarton/MSBump总结ASP.NET Core 相对传统 ASP.NET 有了不少区别,目前也有一定的限制。本文仅涵盖了我自己所遇到的问题,也一定还有很多我没有遇到过的情况。本文转载自公众号文章:https://mp.weixin.qq.com/s/SxFAUV5_8xpJY6R8inLSvA
  • [技术干货] 【趁热打“帖”】Asp.net core实现北向应用服务对接OceanConnect
        华为IoT教程和帮助文档给出的Demo唯独缺少.net的样例,在上次刚刚实现了Asp.net core作为服务对接。使用的Api接口:login/subscriptions/deviceCommands主动调用的接口deviceDataChanged/commandChanged提供给回调的服务调用OceanConnect接口特点header信息app_key为header必须的除了login其他接口的header必须带token请求ContentType分为2种application/x-www-form-urlencoded和application/json 请求必须携带认证证书(证书见附件,密码IoM@1234)基于以上可以总结出通用请求方法/// <summary> /// IoT Post请求 /// </summary> /// <param name="url">完整url</param> /// <param name="content">HttpContent或其子类</param> /// <param name="token">有效token</param> /// <returns></returns> public async Task<string> Post2(string url, HttpContent content, string token) { var handler = new HttpClientHandler { CheckCertificateRevocationList = false, ClientCertificateOptions = ClientCertificateOption.Manual, SslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 }; content.Headers.Add("app_key", AppId); if (content is FormUrlEncodedContent) content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded"); else if (content is StringContent) content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); handler.ClientCertificates.Add(new X509Certificate2(CertificateFilePath, CertificatePassword)); handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; }; using (var client = new HttpClient(handler)) { if (!string.IsNullOrEmpty(token)) { var authValue = new AuthenticationHeaderValue("Bearer", token); client.DefaultRequestHeaders.Authorization = authValue; } HttpResponseMessage response = await client.PostAsync(url, content); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); } }登陆方法public LoginResult Login() { var url = "https://ip:port/iocm/app/sec/v1.1.0/login"; var dic = new Dictionary<string, string> { { "appId", AppId }, { "secret", Secret } }; var body = new FormUrlEncodedContent(dic); try { var result = helper.Post2(url, body, null).GetAwaiter().GetResult(); var login = JsonConvert.DeserializeObject<LoginResult>(result); Token = login.AccessToken; return login; } catch (Exception ex) { _log.LogError(ex, "Login 异常:"); return null; } }订阅deviceDataChanged消息public string Subscript() { CheckToken(); var url = "https://ip:port/iocm/app/sub/v1.2.0/subscriptions?ownerFlag=true"; var param = new Dictionary<string, string> { { "appId", AppId }, { "notifyType", "deviceDataChanged" }, { "callbackUrl", "http://ip:port/api/clock/DeviceDataChanged" }, { "channel", "http" } }; var body = JsonConvert.SerializeObject(param); try { var html = helper.Post2(url, new StringContent(body), Token).GetAwaiter().GetResult(); var result = JsonConvert.DeserializeObject<IoTSubscriptResult>(html); return html; } catch (Exception ex) { _log.LogError(ex, "Subscript 异常"); return ex.Message; } }一个通用的设备命令方法private bool SendDeviceCommands(IoTCmdReq param) { CheckToken(); var url = $"https://ip:port/iocm/app/cmd/v1.4.0/deviceCommands?appId={AppId}"; var body = JsonConvert.SerializeObject(param, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() }); try { var html = helper.Post2(url, new StringContent(body), Token).GetAwaiter().GetResult(); var result = JsonConvert.DeserializeObject<IoTCmdResult>(html); var success = new List<IoTCmdStatus> { IoTCmdStatus.DELIVERED, IoTCmdStatus.PENDING, IoTCmdStatus.SENT, IoTCmdStatus.SUCCESSFUL }; return success.Contains(result.Status); } catch (Exception ex) { _log.LogError(ex, "SendDeviceCommands 异常"); return false; } }一个设备命令样例private bool SetCall(string content, string deviceId) { var param = new IoTCmdReq { DeviceId = deviceId, Command = new IoTCmd { ServiceId = "Call", Method = "Set_Call", Paras = new Dictionary<string, object> { { "content", content } } }, CallbackUrl = "http://ip:port/api/clock/CommandChanged", ExpireTime = 10, MaxRetransmit = 2 }; return SendDeviceCommands(param); }接收回调设备数据变化命令/// <summary> /// 订阅数据变化回调入口 /// </summary> [HttpPost] [Route("[action]")] public void DeviceDataChanged() { string inputbody; using (var reader = new System.IO.StreamReader(HttpContext.Request.Body, Encoding.UTF8)) { inputbody = reader.ReadToEnd(); } var reqdata = JsonConvert.DeserializeObject<IoTDataChangedReq>(inputbody); if (reqdata.Service.ServiceId == "Clock") { _service.Welcome(reqdata.Service.Data["card_no"].ToString(), reqdata.DeviceId); } else if (reqdata.Service.ServiceId == "Sensor") { } }