How to create url with complex query - api

I use dart and flutter for mobile app. I use my api to get data from server. But I found a problem, maybe its dart core problem.
I need to add complex queryParams to my URL like
Map<String, Map<String, List<String>>>{"a": {"b": ["c","d"]}, "e": {}}
I use Uri.parse(url).replace(queryParams: myQueryParams).toString()
But Uri.replace() accepts only Map<String, Iterable<String>> and throws an error
Unhandled Exception: type '_InternalLinkedHashMap<String, List<String>>' is not a subtype of type 'Iterable<dynamic>'
I found method which throws this error
static String _makeQuery(String query, int start, int end,
Map<String, dynamic /*String|Iterable<String>*/ > queryParameters) {
if (query != null) {
if (queryParameters != null) {
throw ArgumentError('Both query and queryParameters specified');
}
return _normalizeOrSubstring(query, start, end, _queryCharTable,
escapeDelimiters: true);
}
if (queryParameters == null) return null;
var result = StringBuffer();
var separator = "";
void writeParameter(String key, String value) {
result.write(separator);
separator = "&";
result.write(Uri.encodeQueryComponent(key));
if (value != null && value.isNotEmpty) {
result.write("=");
result.write(Uri.encodeQueryComponent(value));
}
}
queryParameters.forEach((key, value) {
if (value == null || value is String) {
writeParameter(key, value);
} else {
Iterable values = value;
for (String value in values) {
writeParameter(key, value);
}
}
});
return result.toString();
}
So my question is there is some method in dart to add my queryParams to url or I need to create it by my own?

I have modified original method and now its work.
class UrlCreator {
static String addQueryParams(String url, Map<String, dynamic> queryParams) {
var result = StringBuffer();
var separator = "";
void writeParameter(String key, String value) {
result.write(separator);
separator = "&";
result.write(Uri.encodeQueryComponent(key));
if (value != null && value.isNotEmpty) {
result.write("=");
result.write(Uri.encodeQueryComponent(value));
}
}
void buildQuery(Map queryParams, {parentKey}){
queryParams.forEach((key, value){
print("parentKey = $parentKey Key = $key value = $value");
if (value == null || value is String) {
var newKey = parentKey != null ? "$parentKey[$key]" : key;
writeParameter(newKey, value);
} else if (value is Map) {
buildQuery(value, parentKey: key);
} else {
Iterable values = value;
var newKey = parentKey != null ? "$parentKey[$key][]" : "$key[]";
for (String value in values) {
writeParameter(newKey, value);
}
}
});
}
buildQuery(queryParams);
return url + "?" + result.toString();
}
}

Related

Make [FromQuery] bool testValue accept 'testValue', 'test_value' and 'test-value'

In ASP NET 6+ I need to make [FromQuery] replace underscores _ and minuses - before matching names.
So I want to plumb ASP to allow [FromQuery] bool testValue to be equivalent to all at once:
[FromQuery(Name="testValue")] bool testValue
[FromQuery(Name="test-value")] bool testValue
[FromQuery(Name="test_value")] bool testValue
Is there a place in the pipeline I can get in before names are compared (to remove _ and - myself)?
My current solution is just to replace the Request.Query with my own doctored QueryCollection that duplicates variables with fixed names in a middleware.
But I'm looking for any answer that's more... unhacky?!
public class RequeryMiddleware : IMiddleware
{
private static readonly char[] separators = new[] { '_', '-', '.', '|' };
private static bool Requery(ref string name)
{
bool changed = false;
if (name.IndexOfAny(separators) >= 0)
{
name = string.Concat(name.Split(separators, StringSplitOptions.None));
changed = true;
}
return changed;
}
public Task InvokeAsync(HttpContext context, RequestDelegate next)
{
Dictionary<string, StringValues> mods = new(
StringComparer.OrdinalIgnoreCase
);
foreach (var item in context.Request.Query)
{
string key = item.Key;
if (Requery(ref key))
{
mods.Add(key, item.Value);
}
}
if (mods.Count > 0)
{
Dictionary<string, StringValues> query = new(
context.Request.Query.Count + mods.Count
, StringComparer.OrdinalIgnoreCase
);
foreach (var item in context.Request.Query)
{
query.Add(item.Key, item.Value);
}
foreach (var mod in mods)
{
// if we get here it's bad...
query.TryAdd(mod.Key, mod.Value);
}
// replace the Query collection
context.Request.Query = new QueryCollection(query);
// change the QueryString too
QueryBuilder qb = new(context.Request.Query);
context.Request.QueryString = qb.ToQueryString();
}
return next(context);
}
}

Swashbuckle Swagger - Pulling information from Attributes and putting it into the Schema definition

I am trying to have pull the DisplayAttribute and the DescriptionAttribute from parts of the Swagger Model. For example I may have a Body Parameter which has properties with attributes, which I would also want to be generated in the swagger.json and visible in SwaggerUI.
So far I think the approach that should work would be using a custom filter with swashbuckle. I got a proof of concept using the IParameterFilter which displays the description attribute, not sure if another filter would be better.
Issues:
Finding the key for the schemaRegistry fails for some types, like list.
Need to get the key for the parameter to be generated the same as swagger.
Might need recursion to loop through child properties that contain complex objects.
public class SwaggerParameterFilter : IParameterFilter
{
private SchemaRegistrySettings _settings;
private SchemaIdManager _schemaIdManager;
public SwaggerParameterFilter(SchemaRegistrySettings settings = null)
{
this._settings = settings ?? new SchemaRegistrySettings();
this._schemaIdManager = new SchemaIdManager(this._settings.SchemaIdSelector);
}
public void Apply(IParameter parameter, ParameterFilterContext context)
{
try
{
if (context.ApiParameterDescription?.ModelMetadata?.Properties == null) return;
if (parameter is BodyParameter bodyParameter)
{
string idFor = _schemaIdManager.IdFor(context.ApiParameterDescription.Type);
var schemaRegistry = (SchemaRegistry)context.SchemaRegistry;
//not perfect, crashes with some cases
var schema = schemaRegistry.Definitions[idFor];
//bodyParameter.Schema, this doesn't seem right, no properties
foreach (var modelMetadata in context.ApiParameterDescription.ModelMetadata.Properties)
{
if (modelMetadata is DefaultModelMetadata defaultModelMetadata)
{
//not sure right now how to get the right key for the schema.Properties...
var name = defaultModelMetadata.Name;
name = Char.ToLowerInvariant(name[0]) + name.Substring(1);
if (schema.Properties.ContainsKey(name))
{
var subSchema = schema.Properties[name];
var attributes = defaultModelMetadata.Attributes.Attributes.Select(x => (Attribute)x);
var descriptionAttribute = (DescriptionAttribute)attributes.FirstOrDefault(x => x is DescriptionAttribute);
if (descriptionAttribute != null)
subSchema.Description = descriptionAttribute.Description;
}
}
}
}
}
catch (Exception e)
{
//eat because above is broken
}
}
}
Edit add looping.
public class SwaggerParameterFilter : IParameterFilter
{
private SchemaRegistrySettings _settings;
private SchemaIdManager _schemaIdManager;
public SwaggerParameterFilter(SchemaRegistrySettings settings = null)
{
this._settings = settings ?? new SchemaRegistrySettings();
this._schemaIdManager = new SchemaIdManager(this._settings.SchemaIdSelector);
}
public void Apply(IParameter parameter, ParameterFilterContext context)
{
try
{
if (context.ApiParameterDescription?.ModelMetadata?.Properties == null) return;
//Only BodyParameters are complex and stored in the schema
if (parameter is BodyParameter bodyParameter)
{
var idFor = _schemaIdManager.IdFor(context.ApiParameterDescription.Type);
//not perfect, crashes with some cases
var schema = context.SchemaRegistry.Definitions[idFor];
UpdateSchema(schema, (SchemaRegistry) context.SchemaRegistry, context.ApiParameterDescription.ModelMetadata);
}
}
catch (Exception e)
{
//eat because above is broken
}
}
private void UpdateSchema(Schema schema, SchemaRegistry schemaRegistry, ModelMetadata modelMetadata)
{
if (schema.Ref != null)
{
var schemaReference = schema.Ref.Replace("#/definitions/", "");
UpdateSchema(schemaRegistry.Definitions[schemaReference], schemaRegistry, modelMetadata);
return;
}
if (schema.Properties == null) return;
foreach (var properties in modelMetadata.Properties)
{
if (properties is DefaultModelMetadata defaultModelMetadata)
{
//not sure right now how to get the right key for the schema.Properties...
var name = defaultModelMetadata.Name;
name = Char.ToLowerInvariant(name[0]) + name.Substring(1);
if (schema.Properties.ContainsKey(name) == false) return;
var subSchema = schema.Properties[name];
var attributes = defaultModelMetadata.Attributes.Attributes.Select(x => (Attribute) x).ToList();
var descriptionAttribute =
(DescriptionAttribute) attributes.FirstOrDefault(x => x is DescriptionAttribute);
if (descriptionAttribute != null)
subSchema.Description = descriptionAttribute.Description;
var displayAttribute = (DisplayAttribute) attributes.FirstOrDefault(x => x is DisplayAttribute);
if (displayAttribute != null)
subSchema.Title = displayAttribute.Name;
if (modelMetadata.ModelType.IsPrimitive) return;
UpdateSchema(subSchema, schemaRegistry, defaultModelMetadata);
}
}
}
}
Operation Filter
public class SwaggerOperationFilter : IOperationFilter
{
private SchemaRegistrySettings _settings;
private SchemaIdManager _schemaIdManager;
private IModelMetadataProvider _metadataProvider;
public SwaggerOperationFilter(IModelMetadataProvider metadataProvider, SchemaRegistrySettings settings = null)
{
this._metadataProvider = metadataProvider;
this._settings = settings ?? new SchemaRegistrySettings();
this._schemaIdManager = new SchemaIdManager(this._settings.SchemaIdSelector);
}
public void Apply(Operation operation, OperationFilterContext context)
{
try
{
foreach (var paramDescription in context.ApiDescription.ParameterDescriptions)
{
if (paramDescription?.ModelMetadata?.Properties == null)
{
continue;
}
if (paramDescription.ModelMetadata.ModelType.IsPrimitive)
{
continue;
}
if (paramDescription.ModelMetadata.ModelType == typeof(string))
{
continue;
}
var idFor = _schemaIdManager.IdFor(paramDescription.Type);
var schema = context.SchemaRegistry.Definitions[idFor];
UpdateSchema(schema, (SchemaRegistry)context.SchemaRegistry, paramDescription.ModelMetadata);
}
}
catch (Exception e)
{
//eat because above is broken
}
}
private void UpdateSchema(Schema schema, SchemaRegistry schemaRegistry, ModelMetadata modelMetadata)
{
if (schema.Ref != null)
{
var schemaReference = schema.Ref.Replace("#/definitions/", "");
UpdateSchema(schemaRegistry.Definitions[schemaReference], schemaRegistry, modelMetadata);
return;
}
if (schema.Type == "array")
{
if (schema.Items.Ref != null)
{
var schemaReference = schema.Items.Ref.Replace("#/definitions/", "");
var modelTypeGenericTypeArgument = modelMetadata.ModelType.GenericTypeArguments[0];
modelMetadata = _metadataProvider.GetMetadataForType(modelTypeGenericTypeArgument);
UpdateSchema(schemaRegistry.Definitions[schemaReference], schemaRegistry, modelMetadata);
}
return;
}
if (schema.Properties == null) return;
foreach (var properties in modelMetadata.Properties)
{
if (properties is DefaultModelMetadata defaultModelMetadata)
{
//not sure right now how to get the right key for the schema.Properties...
var name = defaultModelMetadata.Name;
name = Char.ToLowerInvariant(name[0]) + name.Substring(1);
if (schema.Properties.ContainsKey(name) == false) return;
var subSchema = schema.Properties[name];
var attributes = defaultModelMetadata.Attributes.Attributes.Select(x => (Attribute)x).ToList();
var descriptionAttribute =
(DescriptionAttribute)attributes.FirstOrDefault(x => x is DescriptionAttribute);
if (descriptionAttribute != null)
subSchema.Description = descriptionAttribute.Description;
var displayAttribute = (DisplayAttribute)attributes.FirstOrDefault(x => x is DisplayAttribute);
if (displayAttribute != null)
subSchema.Title = displayAttribute.Name;
if (defaultModelMetadata.ModelType.IsPrimitive) return;
UpdateSchema(subSchema, schemaRegistry, defaultModelMetadata);
}
}
}
}
So after some troubleshooting this seems to work for me but may need modification for other cases.
public class SwashbuckleAttributeReaderDocumentFilter : IDocumentFilter
{
private readonly SchemaIdManager _schemaIdManager;
private readonly IModelMetadataProvider _metadataProvider;
private List<string> _updatedSchemeList;
public SwashbuckleAttributeReaderDocumentFilter(IModelMetadataProvider metadataProvider, SchemaRegistrySettings settings = null)
{
_metadataProvider = metadataProvider;
var registrySettings = settings ?? new SchemaRegistrySettings();
_schemaIdManager = new SchemaIdManager(registrySettings.SchemaIdSelector);
}
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
{
_updatedSchemeList = new List<string>();
foreach (var apiDescription in context.ApiDescriptions)
{
foreach (var responseTypes in apiDescription.SupportedResponseTypes)
{
ProcessModelMetadata(context, responseTypes.ModelMetadata);
}
foreach (var paramDescription in apiDescription.ParameterDescriptions)
{
ProcessModelMetadata(context, paramDescription.ModelMetadata);
}
}
}
private void ProcessModelMetadata(DocumentFilterContext context, ModelMetadata currentModelMetadata)
{
if (currentModelMetadata?.Properties == null)
{
return;
}
if (currentModelMetadata.ModelType.IsValueType)
{
return;
}
if (currentModelMetadata.ModelType == typeof(string))
{
return;
}
if (currentModelMetadata.ModelType.IsGenericType)
{
foreach (var modelType in currentModelMetadata.ModelType.GenericTypeArguments)
{
var modelMetadata = _metadataProvider.GetMetadataForType(modelType);
UpdateSchema(context.SchemaRegistry, modelMetadata);
}
}
else if (currentModelMetadata.IsCollectionType)
{
var modelType = currentModelMetadata.ModelType.GetElementType();
var modelMetadata = _metadataProvider.GetMetadataForType(modelType);
UpdateSchema(context.SchemaRegistry, modelMetadata);
}
else
{
UpdateSchema(context.SchemaRegistry, currentModelMetadata);
}
}
public static void SetSchema(Schema schema, ModelMetadata modelMetadata)
{
if (!(modelMetadata is DefaultModelMetadata metadata)) return;
var attributes = GetAtributes(metadata);
SetDescription(attributes, schema);
SetTitle(attributes, schema);
}
private static List<Attribute> GetAtributes(DefaultModelMetadata modelMetadata)
{
return modelMetadata.Attributes.Attributes.Select(x => (Attribute)x).ToList();
}
private static void SetTitle(List<Attribute> attributes, Schema schema)
{
//LastOrDefault because we want the attribute from the dervived class.
var displayAttribute = (DisplayNameAttribute)attributes.LastOrDefault(x => x is DisplayNameAttribute);
if (displayAttribute != null)
schema.Title = displayAttribute.DisplayName;
}
private static void SetDescription(List<Attribute> attributes, Schema schema)
{
//LastOrDefault because we want the attribute from the dervived class. not sure if this works.
var descriptionAttribute = (DescriptionAttribute)attributes.LastOrDefault(x => x is DescriptionAttribute);
if (descriptionAttribute != null)
schema.Description = descriptionAttribute.Description;
}
private void UpdateSchema(ISchemaRegistry schemaRegistry, ModelMetadata modelMetadata, Schema schema = null)
{
if (modelMetadata.ModelType.IsValueType) return;
if (modelMetadata.ModelType == typeof(string)) return;
var idFor = _schemaIdManager.IdFor(modelMetadata.ModelType);
if (_updatedSchemeList.Contains(idFor))
return;
if (schema == null || schema.Ref != null)
{
if (schemaRegistry.Definitions.ContainsKey(idFor) == false) return;
schema = schemaRegistry.Definitions[idFor];
}
_updatedSchemeList.Add(idFor);
SetSchema(schema, modelMetadata);
if (schema.Type == "array")//Array Schema
{
var metaData = _metadataProvider.GetMetadataForType(modelMetadata.ModelType.GenericTypeArguments[0]);
UpdateSchema(schemaRegistry, metaData);
}
else//object schema
{
if (schema.Properties == null)
{
return;
}
foreach (var properties in modelMetadata.Properties)
{
if (!(properties is DefaultModelMetadata defaultModelMetadata))
{
continue;
}
var name = ToLowerCamelCase(defaultModelMetadata.Name);
if (schema.Properties.ContainsKey(name) == false)
{
//when this doesn't match the json object naming.
return;
}
var subSchema = schema.Properties[name];
SetSchema(subSchema, defaultModelMetadata);
UpdateSchema(schemaRegistry, defaultModelMetadata, subSchema);
}
}
}
private static string ToLowerCamelCase(string inputString)
{
if (inputString == null) return null;
if (inputString == string.Empty) return string.Empty;
if (char.IsLower(inputString[0])) return inputString;
return inputString.Substring(0, 1).ToLower() + inputString.Substring(1);
}
}

Create a Gson TypeAdapter for a Guava Range

I am trying to serialize Guava Range objects to JSON using Gson, however the default serialization fails, and I'm unsure how to correctly implement a TypeAdapter for this generic type.
Gson gson = new Gson();
Range<Integer> range = Range.closed(10, 20);
String json = gson.toJson(range);
System.out.println(json);
Range<Integer> range2 = gson.fromJson(json,
new TypeToken<Range<Integer>>(){}.getType());
System.out.println(range2);
assertEquals(range2, range);
This fails like so:
{"lowerBound":{"endpoint":10},"upperBound":{"endpoint":20}}
PASSED: typeTokenInterface
FAILED: range
java.lang.RuntimeException: Unable to invoke no-args constructor for
com.google.common.collect.Cut<java.lang.Integer>. Register an
InstanceCreator with Gson for this type may fix this problem.
at com.google.gson.internal.ConstructorConstructor$12.construct(
ConstructorConstructor.java:210)
...
Note that the default serialization actually loses information - it fails to report whether the endpoints are open or closed. I would prefer to see it serialized similar to its toString(), e.g. [10‥20] however simply calling toString() won't work with generic Range instances, as the elements of the range may not be primitives (Joda-Time LocalDate instances, for example). For the same reason, implementing a custom TypeAdapter seems difficult, as we don't know how to deserialize the endpoints.
I've implemented most of a TypeAdaptorFactory based on the template provided for Multimap which ought to work, but now I'm stuck on the generics. Here's what I have so far:
public class RangeTypeAdapterFactory implements TypeAdapterFactory {
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
Type type = typeToken.getType();
if (typeToken.getRawType() != Range.class
|| !(type instanceof ParameterizedType)) {
return null;
}
Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
TypeAdapter<?> elementAdapter = (TypeAdapter<?>)gson.getAdapter(TypeToken.get(elementType));
// Bound mismatch: The generic method newRangeAdapter(TypeAdapter<E>) of type
// GsonUtils.RangeTypeAdapterFactory is not applicable for the arguments
// (TypeAdapter<capture#4-of ?>). The inferred type capture#4-of ? is not a valid
// substitute for the bounded parameter <E extends Comparable<?>>
return (TypeAdapter<T>) newRangeAdapter(elementAdapter);
}
private <E extends Comparable<?>> TypeAdapter<Range<E>> newRangeAdapter(final TypeAdapter<E> elementAdapter) {
return new TypeAdapter<Range<E>>() {
#Override
public void write(JsonWriter out, Range<E> value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
String repr = (value.lowerBoundType() == BoundType.CLOSED ? "[" : "(") +
(value.hasLowerBound() ? elementAdapter.toJson(value.lowerEndpoint()) : "-\u221e") +
'\u2025' +
(value.hasLowerBound() ? elementAdapter.toJson(value.upperEndpoint()) : "+\u221e") +
(value.upperBoundType() == BoundType.CLOSED ? "]" : ")");
out.value(repr);
}
public Range<E> read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
String[] endpoints = in.nextString().split("\u2025");
E lower = elementAdapter.fromJson(endpoints[0].substring(1));
E upper = elementAdapter.fromJson(endpoints[1].substring(0,endpoints[1].length()-1));
return Range.range(lower, endpoints[0].charAt(0) == '[' ? BoundType.CLOSED : BoundType.OPEN,
upper, endpoints[1].charAt(endpoints[1].length()-1) == '[' ? BoundType.CLOSED : BoundType.OPEN);
}
};
}
}
However the return (TypeAdapter<T>) newRangeAdapter(elementAdapter); line has a compilation error and I'm now at a loss.
What's the best way to resolve this error? Is there a better way to serialize Range objects that I'm missing? What about if I want to serialize RangeSets?
Rather frustrating that the Google utility library and Google serialization library seem to require so much glue to work together :(
This feels somewhat like reinventing the wheel, but it was a lot quicker to put together and test than the time spent trying to get Gson to behave, so at least presently I'll be using the following Converters to serialize Range and RangeSet*, rather than Gson.
/**
* Converter between Range instances and Strings, essentially a custom serializer.
* Ideally we'd let Gson or Guava do this for us, but presently this is cleaner.
*/
public static <T extends Comparable<? super T>> Converter<Range<T>, String> rangeConverter(final Converter<T, String> elementConverter) {
final String NEG_INFINITY = "-\u221e";
final String POS_INFINITY = "+\u221e";
final String DOTDOT = "\u2025";
return new Converter<Range<T>, String>() {
#Override
protected String doForward(Range<T> range) {
return (range.hasLowerBound() && range.lowerBoundType() == BoundType.CLOSED ? "[" : "(") +
(range.hasLowerBound() ? elementConverter.convert(range.lowerEndpoint()) : NEG_INFINITY) +
DOTDOT +
(range.hasUpperBound() ? elementConverter.convert(range.upperEndpoint()) : POS_INFINITY) +
(range.hasUpperBound() && range.upperBoundType() == BoundType.CLOSED ? "]" : ")");
}
#Override
protected Range<T> doBackward(String range) {
String[] endpoints = range.split(DOTDOT);
Range<T> ret = Range.all();
if(!endpoints[0].substring(1).equals(NEG_INFINITY)) {
T lower = elementConverter.reverse().convert(endpoints[0].substring(1));
ret = ret.intersection(Range.downTo(lower, endpoints[0].charAt(0) == '[' ? BoundType.CLOSED : BoundType.OPEN));
}
if(!endpoints[1].substring(0,endpoints[1].length()-1).equals(POS_INFINITY)) {
T upper = elementConverter.reverse().convert(endpoints[1].substring(0,endpoints[1].length()-1));
ret = ret.intersection(Range.upTo(upper, endpoints[1].charAt(endpoints[1].length()-1) == ']' ? BoundType.CLOSED : BoundType.OPEN));
}
return ret;
}
};
}
/**
* Converter between RangeSet instances and Strings, essentially a custom serializer.
* Ideally we'd let Gson or Guava do this for us, but presently this is cleaner.
*/
public static <T extends Comparable<? super T>> Converter<RangeSet<T>, String> rangeSetConverter(final Converter<T, String> elementConverter) {
return new Converter<RangeSet<T>, String>() {
private final Converter<Range<T>, String> rangeConverter = rangeConverter(elementConverter);
#Override
protected String doForward(RangeSet<T> rs) {
ArrayList<String> ls = new ArrayList<>();
for(Range<T> range : rs.asRanges()) {
ls.add(rangeConverter.convert(range));
}
return Joiner.on(", ").join(ls);
}
#Override
protected RangeSet<T> doBackward(String rs) {
Iterable<String> parts = Splitter.on(",").trimResults().split(rs);
ImmutableRangeSet.Builder<T> build = ImmutableRangeSet.builder();
for(String range : parts) {
build.add(rangeConverter.reverse().convert(range));
}
return build.build();
}
};
}
*For inter-process communication, Java serialization would likely work just fine, as both classes implement Serializable. However I'm serializing to disk for more permanent storage, meaning I need a format I can trust won't change over time. Guava's serialization doesn't provide that guarantee.
Here is a Gson JsonSerializer and JsonDeserializer that generically supports a Range: https://github.com/jamespedwards42/Fava/wiki/Range-Marshaller
#Override
public JsonElement serialize(final Range src, final Type typeOfSrc, final JsonSerializationContext context) {
final JsonObject jsonObject = new JsonObject();
if ( src.hasLowerBound() ) {
jsonObject.add( "lowerBoundType", context.serialize( src.lowerBoundType() ) );
jsonObject.add( "lowerBound", context.serialize( src.lowerEndpoint() ) );
} else
jsonObject.add( "lowerBoundType", context.serialize( BoundType.OPEN ) );
if ( src.hasUpperBound() ) {
jsonObject.add( "upperBoundType", context.serialize( src.upperBoundType() ) );
jsonObject.add( "upperBound", context.serialize( src.upperEndpoint() ) );
} else
jsonObject.add( "upperBoundType", context.serialize( BoundType.OPEN ) );
return jsonObject;
}
#Override
public Range<? extends Comparable<?>> deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context) throws JsonParseException {
if ( !( typeOfT instanceof ParameterizedType ) )
throw new IllegalStateException( "typeOfT must be a parameterized Range." );
final JsonObject jsonObject = json.getAsJsonObject();
final JsonElement lowerBoundTypeJsonElement = jsonObject.get( "lowerBoundType" );
final JsonElement upperBoundTypeJsonElement = jsonObject.get( "upperBoundType" );
if ( lowerBoundTypeJsonElement == null || upperBoundTypeJsonElement == null )
throw new IllegalStateException( "Range " + json
+ "was not serialized with this serializer! The default serialization does not store the boundary types, therfore we can not deserialize." );
final Type type = ( ( ParameterizedType ) typeOfT ).getActualTypeArguments()[0];
final BoundType lowerBoundType = context.deserialize( lowerBoundTypeJsonElement, BoundType.class );
final JsonElement lowerBoundJsonElement = jsonObject.get( "lowerBound" );
final Comparable<?> lowerBound = lowerBoundJsonElement == null ? null : context.deserialize( lowerBoundJsonElement, type );
final BoundType upperBoundType = context.deserialize( upperBoundTypeJsonElement, BoundType.class );
final JsonElement upperBoundJsonElement = jsonObject.get( "upperBound" );
final Comparable<?> upperBound = upperBoundJsonElement == null ? null : context.deserialize( upperBoundJsonElement, type );
if ( lowerBound == null && upperBound != null )
return Range.upTo( upperBound, upperBoundType );
else if ( lowerBound != null && upperBound == null )
return Range.downTo( lowerBound, lowerBoundType );
else if ( lowerBound == null && upperBound == null )
return Range.all();
return Range.range( lowerBound, lowerBoundType, upperBound, upperBoundType );
}
Here is a straight forward solution. Works very well
import com.google.common.collect.BoundType;
import com.google.common.collect.Range;
import com.google.gson.*;
import java.lang.reflect.Type;
public class GoogleRangeAdapter implements JsonSerializer, JsonDeserializer {
public static String TK_hasLowerBound = "hasLowerBound";
public static String TK_hasUpperBound = "hasUpperBound";
public static String TK_lowerBoundType = "lowerBoundType";
public static String TK_upperBoundType = "upperBoundType";
public static String TK_lowerBound = "lowerBound";
public static String TK_upperBound = "upperBound";
#Override
public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = (JsonObject)json;
boolean hasLowerBound = jsonObject.get(TK_hasLowerBound).getAsBoolean();
boolean hasUpperBound = jsonObject.get(TK_hasUpperBound).getAsBoolean();
if (!hasLowerBound && !hasUpperBound) {
return Range.all();
}
else if (!hasLowerBound && hasUpperBound){
double upperBound = jsonObject.get(TK_upperBound).getAsDouble();
BoundType upperBoundType = BoundType.valueOf(jsonObject.get(TK_upperBoundType).getAsString());
if (upperBoundType == BoundType.OPEN)
return Range.lessThan(upperBound);
else
return Range.atMost(upperBound);
}
else if (hasLowerBound && !hasUpperBound){
double lowerBound = jsonObject.get(TK_lowerBound).getAsDouble();
BoundType lowerBoundType = BoundType.valueOf(jsonObject.get(TK_lowerBoundType).getAsString());
if (lowerBoundType == BoundType.OPEN)
return Range.greaterThan(lowerBound);
else
return Range.atLeast(lowerBound);
}
else {
double lowerBound = jsonObject.get(TK_lowerBound).getAsDouble();
double upperBound = jsonObject.get(TK_upperBound).getAsDouble();
BoundType upperBoundType = BoundType.valueOf(jsonObject.get(TK_upperBoundType).getAsString());
BoundType lowerBoundType = BoundType.valueOf(jsonObject.get(TK_lowerBoundType).getAsString());
if (lowerBoundType == BoundType.OPEN && upperBoundType == BoundType.OPEN)
return Range.open(lowerBound, upperBound);
else if (lowerBoundType == BoundType.OPEN && upperBoundType == BoundType.CLOSED)
return Range.openClosed(lowerBound, upperBound);
else if (lowerBoundType == BoundType.CLOSED && upperBoundType == BoundType.OPEN)
return Range.closedOpen(lowerBound, upperBound);
else
return Range.closed(lowerBound, upperBound);
}
}
#Override
public JsonElement serialize(Object src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jsonObject = new JsonObject();
Range<Double> range = (Range<Double>)src;
boolean hasLowerBound = range.hasLowerBound();
boolean hasUpperBound = range.hasUpperBound();
jsonObject.addProperty(TK_hasLowerBound, hasLowerBound);
jsonObject.addProperty(TK_hasUpperBound, hasUpperBound);
if (hasLowerBound) {
jsonObject.addProperty(TK_lowerBound, range.lowerEndpoint());
jsonObject.addProperty(TK_lowerBoundType, range.lowerBoundType().name());
}
if (hasUpperBound) {
jsonObject.addProperty(TK_upperBound, range.upperEndpoint());
jsonObject.addProperty(TK_upperBoundType, range.upperBoundType().name());
}
return jsonObject;
}
}

Convert cookie string to a Cookie object in C# or Java

I need to automatically access a website that requires authentication. I found cookie string of this website's http host (using fiddler). Is there a way to convert this string to a cookie object and pass it to a Webclient to pass the authentication?
Convert the Sting to a cookie object. For this you need to parse the String to get name, value, path, domain, etc.
You have to do something like this -
String[] cArray = cookieValueIs.split(";");
for (String s : cArray) {
s = s.trim();
int i1 = s.indexOf('=');
if (i1 != -1) {
String k = s.substring(0, i1).trim();
String v = s.substring(i1 + 1).trim();
if (k.equalsIgnoreCase(VERSION)) {
version = v;
} else if (k.equalsIgnoreCase(COMMENT)) {
comment = v;
} else if (k.equalsIgnoreCase(DOMAIN)) {
domain = v;
} else if (k.equalsIgnoreCase(PATH)) {
path = v;
} else if (k.equalsIgnoreCase(MAX_AGE)) {
maxAge = v;
} else if(k.equalsIgnoreCase(EXPIRES)){
continue;
}
else {
key = k;
value = v;
}
} else {
if (s.equalsIgnoreCase(SECURE)) {
secure = true;
} else if (s.equalsIgnoreCase(HTTPONLY)) {
httpOnly = true;
}
}
Once you are done with this create a cookie object-
Cookie cookie = new Cookie(key,value);
if(comment != null){
cookie.setComment(comment);
}
if(domain != null){
cookie.setDomain(domain);
}
if(path != null){
cookie.setPath(path);
}
if(version != null){
cookie.setVersion(Integer.parseInt(version));
}
if(secure){
cookie.setSecure(true);
Now your string is converted to the Cookie object --> cookie
This worked for me in c#.
public static Cookie ToCookie(this string #this)
{
String[] array = #this.Split(';');
var cookie = new Cookie();
foreach (var ss in array)
{
string key;
object value;
var s = ss.Trim();
int indexOf = s.IndexOf('=');
if (indexOf != -1) {
key = s.Substring(0, indexOf).Trim();
value = s.Substring(indexOf + 1).Trim();
} else
{
key = s.ToTitleCase();
value = true;
}
var prop = cookie.GetType().GetProperty(key.ToTitleCase());
if (prop != null)
{
var converted = Convert.ChangeType(value, prop.PropertyType);
prop.SetValue(cookie, converted, null);
}else
{
cookie.Name = key;
cookie.Value = value.ToString();
}
}
return cookie;
}

Getting all the Term Stores in Sharepoint 2010 (web services or client-side object model)?

Is it possible with Sharepoint 2010 (not 2013!) to get a list of all the Term Stores on the site using either the web services or the client-side object model?
I know 2013 has added a library for it, but that will not help me on 2010.
If not the whole list, how do I get the Term Store ID, if I know a Term (that might or might not be in the TaxonomyHiddenList)?
Someone mentioned checking out the TaxonomyFieldType fields, so I hacked together these 2 methods. I do not know if these will work under all circumstances.
First function just returns the Term Store ID which is stored in the info of the first TaxonomyFieldType* we come over.
public static string GetDefaultTermStore(string site) {
var context = new ClientContext(site);
var fields = context.Web.Fields;
context.Load(fields, fs => fs.Include(f => f.SchemaXml, f => f.TypeAsString));
context.ExecuteQuery();
foreach (var field in fields) {
if (field.TypeAsString.StartsWith("TaxonomyFieldType")) {
var doc = XDocument.Parse(field.SchemaXml);
var node = doc.XPathSelectElement("//Name[text()='SspId']/../Value");
if (node != null && !string.IsNullOrEmpty(node.Value)) {
return node.Value;
}
}
}
throw new Exception("Term Store ID not found!");
}
The second function goes through all the fields and gets all the possible Term Store IDs and returns them in a list.
public static List<string> GetTermStores(string site) {
var context = new ClientContext(site);
var fields = context.Web.Fields;
context.Load(fields, fs => fs.Include(f => f.SchemaXml, f => f.TypeAsString));
context.ExecuteQuery();
var hashlist = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
foreach (var field in fields) {
if (field.TypeAsString.StartsWith("TaxonomyFieldType")) {
var doc = XDocument.Parse(field.SchemaXml);
var node = doc.XPathSelectElement("//Name[text()='SspId']/../Value");
if (node != null && !string.IsNullOrEmpty(node.Value)) {
if (!hashlist.Contains(node.Value)) {
hashlist.Add(node.Value);
}
}
}
}
if (hashlist.Count == 0) throw new Exception("No Term Store IDs not found!");
return hashlist.ToList();
}
Is this a correct answer to my question do anyone have a more sure way to get the IDs?
Does not seem like anyone else has a good answer for this question.
I have added the utility class I made from this below. Big block of uncommented code below for those who might need:
using Microsoft.SharePoint.Client;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web.Services.Protocols;
using System.Windows.Forms;
using System.Xml.Linq;
using System.Xml.XPath;
namespace VitaminTilKanbanPusher.Sharepoint {
public class SharepointTaxonomyAgent {
//URLS:
//http://www.novolocus.com/2012/02/06/working-with-the-taxonomyclientservice-part-1-what-fields-are-there/
//
public static void Test() {
var site = ConfigurationManager.AppSettings["VitaminSite"];
//var list = ConfigurationManager.AppSettings["VitaminList"];
//var id = GetDefaultTermStore(site);
//var ids = GetTermStores(site);
var rs = GetAllTermSetNames(site);
var ts = GetTermSetTerms(site, "Some Name");
//var ts = GetTermSetTerms(site, "Some other name");
//var term = GetTermInfo(site, "Priority");
//var term2 = GetTermInfo(site, "My term");
//var termset = GetTermSetInfo(site, "My term");
//var termsets = GetTermSets(site, "My term");
}
public static string GetDefaultTermStore(string site) {
var context = new ClientContext(site);
context.ExecutingWebRequest += ctx_MixedAuthRequest;
var fields = context.Web.Fields;
context.Load(fields, fs => fs.Include(f => f.InternalName, f => f.SchemaXml, f => f.TypeAsString));
context.ExecuteQuery();
foreach (var field in fields) {
//field.InternalName== "TaxKeyword" -> possibly default?
if (field.TypeAsString.StartsWith("TaxonomyFieldType")) {
var doc = XDocument.Parse(field.SchemaXml);
var node = doc.XPathSelectElement("//Name[text()='SspId']/../Value");
if (node != null && !string.IsNullOrEmpty(node.Value)) {
return node.Value;
}
}
}
throw new Exception("Term Store ID not found!");
}
public static List<string> GetTermStores(string site) {
var context = new ClientContext(site);
context.ExecutingWebRequest += ctx_MixedAuthRequest;
var fields = context.Web.Fields;
context.Load(fields, fs => fs.Include(f => f.SchemaXml, f => f.TypeAsString));
context.ExecuteQuery();
var hashlist = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
foreach (var field in fields) {
if (field.TypeAsString.StartsWith("TaxonomyFieldType")) {
var doc = XDocument.Parse(field.SchemaXml);
var node = doc.XPathSelectElement("//Name[text()='SspId']/../Value");
if (node != null && !string.IsNullOrEmpty(node.Value)) {
if (!hashlist.Contains(node.Value)) {
hashlist.Add(node.Value);
}
}
}
}
if (hashlist.Count == 0) throw new Exception("No Term Store IDs not found!");
return hashlist.ToList();
}
private static List<TermSet> _termSets;
public static List<TermSet> GetAllTermSetNames(string site, string onlySpecificTermSetName = null) {
if (_termSets != null) {
if (onlySpecificTermSetName == null) return _termSets;
foreach (var ts in _termSets) {
if (ts.Name.Equals(onlySpecificTermSetName, StringComparison.InvariantCultureIgnoreCase)) {
return new List<TermSet>() { ts };
}
}
return new List<TermSet>();
}
var context = new ClientContext(site);
context.ExecutingWebRequest += ctx_MixedAuthRequest;
var fields = context.Web.Fields;
context.Load(fields, fs => fs.Include(f => f.SchemaXml, f => f.TypeAsString));
context.ExecuteQuery();
var hashlist = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
var termSets = new List<TermSet>();
TermSet theChosenTermSet = null;
foreach (var field in fields) {
if (field.TypeAsString.StartsWith("TaxonomyFieldType")) {
var ts = new TermSet();
var doc = XDocument.Parse(field.SchemaXml);
var fn = doc.Element("Field");
if (fn == null) continue;
if (fn.Attribute("DisplayName") == null) continue;
if (fn.Attribute("ID") == null) continue;
ts.Name = fn.Attribute("DisplayName").Value;
//Only 1 set?
if (onlySpecificTermSetName != null) {
if (!ts.Name.Equals(onlySpecificTermSetName, StringComparison.InvariantCultureIgnoreCase)) {
theChosenTermSet = ts;
}
}
if (fn.Attribute("Description") != null) {
ts.Description = fn.Attribute("Description").Value;
}
var node = doc.XPathSelectElement("//Name[text()='SspId']/../Value");
if (node != null && !string.IsNullOrEmpty(node.Value)) {
ts.TermStoreId = node.Value;
}
var node2 = doc.XPathSelectElement("//Name[text()='TermSetId']/../Value");
if (node2 != null && !string.IsNullOrEmpty(node2.Value)) {
ts.Id = node2.Value;
}
else {
continue; //No ID found
}
//Unique hites
if (!hashlist.Contains(ts.Id)) {
hashlist.Add(ts.Id);
termSets.Add(ts);
}
}
}
_termSets = termSets;
if (onlySpecificTermSetName != null) return (theChosenTermSet == null ? new List<TermSet>() : new List<TermSet>() { theChosenTermSet });
return termSets;
}
public static TermSet GetTermSetTerms(string site, string termName) {
var ts = GetAllTermSetNames(site, termName);
if (ts.Count == 0) throw new Exception("Could not find termset: " + termName);
var theTermSet = ts[0];
var proxy = new SharepointTaxWS.Taxonomywebservice();
proxy.UseDefaultCredentials = true;
proxy.PreAuthenticate = true;
proxy.Url = Path.Combine(site, "_vti_bin/taxonomyclientservice.asmx");
GetAuthCookie(proxy, site);
var lciden = 1033; //var lcidno = 1044; // System.Globalization.CultureInfo.CurrentCulture.LCID
var clientTime = DateTime.Now.AddYears(-2).ToUniversalTime().Ticks.ToString();
var termStoreId = new Guid(theTermSet.TermStoreId);// Guid.Parse(theTermSet.TermStoreId);
var termSetId = new Guid(theTermSet.Id);
string clientTimestamps = string.Format("<timeStamp>{0}</timeStamp>", clientTime);
string clientVersion = "<version>1</version>";
string termStoreIds = string.Format("<termStoreId>{0}</termStoreId>", termStoreId.ToString("D"));
string termSetIds = string.Format("<termSetId>{0}</termSetId>", termSetId.ToString("D"));
string serverTermSetTimestampXml;
string result = proxy.GetTermSets(termStoreIds, termSetIds, 1033, clientTimestamps, clientVersion, out serverTermSetTimestampXml);
var term = ParseTermSetInfo(result);
term.Description = theTermSet.Description;
term.Id = theTermSet.Id;
term.Name = theTermSet.Name;
return term;
}
//public static Term GetTermSetInfo(string site, string termName) {
// var proxy = new SharepointTaxWS.Taxonomywebservice();
// proxy.UseDefaultCredentials = true;
// proxy.PreAuthenticate = true;
// proxy.Url = Path.Combine(site, "_vti_bin/taxonomyclientservice.asmx");
// GetAuthCookie(proxy, site);
// var lciden = 1033; //var lcidno = 1044; // System.Globalization.CultureInfo.CurrentCulture.LCID
// var sets = proxy.GetChildTermsInTermSet(Guid.Parse(""), lciden, Guid.Parse("termsetguid"));
// var term = ParseTermInfo(sets);
// return term;
//}
public static Term GetTermInfo(string site, string termName) {
var proxy = new SharepointTaxWS.Taxonomywebservice();
proxy.UseDefaultCredentials = true;
proxy.PreAuthenticate = true;
proxy.Url = Path.Combine(site, "_vti_bin/taxonomyclientservice.asmx");
GetAuthCookie(proxy, site);
var lciden = 1033; //var lcidno = 1044; // System.Globalization.CultureInfo.CurrentCulture.LCID
var sets = proxy.GetTermsByLabel(termName, lciden, SharepointTaxWS.StringMatchOption.StartsWith, 100, null, false);
var term = ParseTermInfo(sets);
return term;
}
private static TermSet ParseTermSetInfo(string xml) {
//Not done
var info = XDocument.Parse(xml);
var ts = new TermSet();
ts.Terms = new List<Term>();
var n1 = info.XPathSelectElements("//T");
if (n1 != null) {
foreach (var item in n1) {
var t = new Term();
t.Id = item.Attribute("a9").Value;
t.Name = item.XPathSelectElement("LS/TL").Attribute("a32").Value;
t.TermSet = ts;
ts.Terms.Add(t);
}
}
return ts;
}
private static Term ParseTermInfo(string xml) {
var info = XDocument.Parse(xml);
var t = new Term();
var ts = new TermSet();
var n1 = info.XPathSelectElement("TermStore/T");
var n2 = info.XPathSelectElement("TermStore/T/LS/TL");
var n3 = info.XPathSelectElement("TermStore/T/TMS/TM");
if (n1 != null && n1.Attribute("a9") != null) {
t.Id = n1.Attribute("a9").Value;
}
if (n2 != null && n2.Attribute("a32") != null) {
t.Name = n2.Attribute("a32").Value;
}
if (n3 != null && n3.Attribute("a24") != null) {
ts.Id = n3.Attribute("a24").Value;
}
if (n3 != null && n3.Attribute("a12") != null) {
ts.Name = n3.Attribute("a12").Value;
}
t.TermSet = ts;
return t;
}
private static CookieCollection _theAuth;
private static bool _bNoClaims;
static void GetAuthCookie(SoapHttpClientProtocol proxy, string site) {
return;
//if (_bNoClaims) {
// return; //Ingen claims.
//}
//// get the cookie collection - authentication workaround
//CookieCollection cook = null;
//try {
// if (_theAuth == null) {
// cook = ClaimClientContext.GetAuthenticatedCookies(site, 925, 525);
// }
// else {
// cook = _theAuth;
// }
// _theAuth = cook;
// _bNoClaims = false;
//}
//catch (ApplicationException ex) {
// if (ex.Message.Contains("claim")) _bNoClaims = true;
// Console.Write("Auth feilet: " + ex.Message + " - ");
// //IGNORE
//}
//if (_theAuth != null) {
// proxy.CookieContainer = new CookieContainer();
// proxy.CookieContainer.Add(_theAuth);
//}
}
static void ctx_MixedAuthRequest(object sender, WebRequestEventArgs e) {
//add the header that tells SharePoint to use Windows Auth
e.WebRequestExecutor.RequestHeaders.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
}
}
public class TermSet {
public string Id { get; set; }
public string Name { get; set; }
public List<Term> Terms { get; set; }
public string TermStoreId { get; set; }
public string Description { get; set; }
public override string ToString() {
int tc = 0;
if (Terms != null) tc = Terms.Count;
return Name + "|" + Id + " (" + tc + "terms)";
}
}
public class Term {
public string Id { get; set; }
public string Name { get; set; }
public TermSet TermSet { get; set; }
public override string ToString() {
return Name + "|" + Id;
}
}
}