如何将SqlGeography类型(Microsoft.SqlServer.Types)作为Web引用传递?
ASMX默认使用的XmlSerializer无法完整序列化SqlGeography这类复杂的自定义类型,只能识别其简单的公共属性(比如STSrid),这就是客户端生成的类仅包含该属性的原因。以下是几种可行的解决方法:
方法1:手动扩展客户端生成的分部类
客户端生成的SqlGeography是分部类,可以在客户端项目中新增一个分部类文件,补充序列化/反序列化逻辑,通过WKT(Well-Known Text)格式传递完整地理数据:
public partial class SqlGeography { // 新增用于传递完整地理数据的WKT属性 public string Wkt { get; set; } // 将当前对象转换为SqlGeography实例 public Microsoft.SqlServer.Types.SqlGeography ToSqlGeography() { return string.IsNullOrEmpty(Wkt) ? null : Microsoft.SqlServer.Types.SqlGeography.STGeomFromText( new System.Data.SqlTypes.SqlChars(Wkt), this.STSrid); } // 从SqlGeography实例初始化当前对象的静态方法 public static SqlGeography FromSqlGeography(Microsoft.SqlServer.Types.SqlGeography geo) { if (geo == null) return null; return new SqlGeography { STSrid = (int)geo.STSrid, Wkt = geo.STAsText().ToString() }; } }
服务端需要将SqlGeography转换为带Wkt属性的对象返回,客户端再通过ToSqlGeography()方法还原为原生类型。
方法2:服务端使用可序列化的包装类
在ASMX服务项目中创建一个包装类,封装SqlGeography的必要数据(WKT、STSrid),服务端方法返回该包装类而非直接返回SqlGeography:
public class SqlGeographyWrapper { public int STSrid { get; set; } public string Wkt { get; set; } // 从SqlGeography实例初始化包装类 public static SqlGeographyWrapper FromSqlGeography(Microsoft.SqlServer.Types.SqlGeography geo) { if (geo == null) return null; return new SqlGeographyWrapper { STSrid = (int)geo.STSrid, Wkt = geo.STAsText().ToString() }; } // 将包装类转换为SqlGeography实例 public Microsoft.SqlServer.Types.SqlGeography ToSqlGeography() { return Microsoft.SqlServer.Types.SqlGeography.STGeomFromText( new System.Data.SqlTypes.SqlChars(Wkt), STSrid); } }
服务端方法示例:
[WebMethod] public SqlGeographyWrapper GetLocation() { var geo = Microsoft.SqlServer.Types.SqlGeography.Point(47.6062, -122.3321, 4326); return SqlGeographyWrapper.FromSqlGeography(geo); }
客户端添加Web引用后,即可通过包装类获取完整的地理数据,再转换为原生SqlGeography类型。
方法3:改用DataContractSerializer(进阶)
ASMX默认使用XmlSerializer,可通过在服务类上标注[DataContractFormat]切换为DataContractSerializer。但由于SqlGeography是第三方类型,需配合数据契约包装类或DataContractSurrogate处理序列化逻辑,该方法复杂度较高,适合有一定WCF序列化经验的场景。
方法4:升级至WCF(长期方案)
如果项目允许,建议将ASMX服务升级为WCF服务。WCF对复杂类型的序列化支持更完善,可通过配置DataContractSerializer或NetDataContractSerializer直接传递SqlGeography类型,同时客户端需适配WCF服务引用。
内容的提问来源于stack exchange,提问作者Peet Brits

