Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Geocoding.sln
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Geocoding.Tests", "test\Geo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Geocoding.Here", "src\Geocoding.Here\Geocoding.Here.csproj", "{41F9E0D3-2094-4CE7-A2CD-F3CAF585A048}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Geocoding.UsCensusBureau", "src\Geocoding.UsCensusBureau\Geocoding.UsCensusBureau.csproj", "{45E82D63-BEC0-4DF2-AC0E-AEB2D235ED5B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -53,6 +55,10 @@ Global
{41F9E0D3-2094-4CE7-A2CD-F3CAF585A048}.Debug|Any CPU.Build.0 = Debug|Any CPU
{41F9E0D3-2094-4CE7-A2CD-F3CAF585A048}.Release|Any CPU.ActiveCfg = Release|Any CPU
{41F9E0D3-2094-4CE7-A2CD-F3CAF585A048}.Release|Any CPU.Build.0 = Release|Any CPU
{45E82D63-BEC0-4DF2-AC0E-AEB2D235ED5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{45E82D63-BEC0-4DF2-AC0E-AEB2D235ED5B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{45E82D63-BEC0-4DF2-AC0E-AEB2D235ED5B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{45E82D63-BEC0-4DF2-AC0E-AEB2D235ED5B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -63,6 +69,7 @@ Global
{27F58640-D424-40F5-945E-42BF8BC872A0} = {F742864D-9400-4CE2-957A-DBD0A0237277}
{9773C7DA-DD1A-490D-B4D8-CEA18804AD1E} = {F742864D-9400-4CE2-957A-DBD0A0237277}
{41F9E0D3-2094-4CE7-A2CD-F3CAF585A048} = {F742864D-9400-4CE2-957A-DBD0A0237277}
{45E82D63-BEC0-4DF2-AC0E-AEB2D235ED5B} = {F742864D-9400-4CE2-957A-DBD0A0237277}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {085E97E6-56E0-4099-94E9-10F9080F2DD1}
Expand Down
37 changes: 37 additions & 0 deletions src/Geocoding.UsCensusBureau/Geocoding.UsCensusBureau.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Description>Includes a model and interface for communicating with four popular Geocoding providers. Current implementations include: Google Maps, Yahoo! PlaceFinder, Bing Maps (aka Virtual Earth), and Mapquest. The API returns latitude/longitude coordinates and normalized address information. This can be used to perform address validation, real time mapping of user-entered addresses, distance calculations, and much more.</Description>
<AssemblyTitle>Geocoding.net UsCensusBureau</AssemblyTitle>
<VersionPrefix>4.0.0-beta1</VersionPrefix>
<Authors>chadly</Authors>
<TargetFrameworks>netstandard1.3;net46</TargetFrameworks>
<AssemblyName>Geocoding.UsCensusBureau</AssemblyName>
<PackageId>Geocoding.UsCensusBureau</PackageId>
<PackageTags>geocoding;geocode;geocoder;maps;address;validation;normalization;google-maps;bing-maps;yahoo-placefinder;mapquest</PackageTags>
<PackageReleaseNotes>https://github.com/chadly/Geocoding.net/releases/latest</PackageReleaseNotes>
<PackageProjectUrl>https://github.com/chadly/Geocoding.net</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/chadly/Geocoding.net/blob/master/LICENSE</PackageLicenseUrl>
<RepositoryUrl>https://github.com/chadly/Geocoding.net.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<Version>4.0.0</Version>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Geocoding.Core\Geocoding.Core.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)'=='netstandard1.3'">
<PackageReference Include="System.Net.Http" Version="4.3.1" />
<PackageReference Include="System.Runtime.Serialization.Json" Version="4.3.0" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)'=='net46'">
<Reference Include="System.Net.Http" />
</ItemGroup>

</Project>
11 changes: 11 additions & 0 deletions src/Geocoding.UsCensusBureau/UsCensusBureauAddress.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Geocoding.UsCensusBureau
{
public class UsCensusBureauAddress : Address
{
public UsCensusBureauAddress(string formattedAddress, Location coordinates)
: base(formattedAddress, coordinates, UsCensusBureauConstants.Provider)
{

}
}
}
19 changes: 19 additions & 0 deletions src/Geocoding.UsCensusBureau/UsCensusBureauConstants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace Geocoding.UsCensusBureau
{
public class UsCensusBureauConstants
{
public const string Provider = "UsCensusBureau";

public const string BaseUrl = "https://geocoding.geo.census.gov/geocoder/";
public const string OneLineAddressPath = "locations/onelineaddress?";
public const string AddressPath = "locations/address?";

public const string AddressMatchesKey = "addressMatches";
public const string MatchedAddressKey = "matchedAddress";
public const string CoordinatesKey = "coordinates";
public const string ResultKey = "result";
public const string ErrorsKey = "errors";
public const string XKey = "x";
public const string YKey = "y";
}
}
98 changes: 98 additions & 0 deletions src/Geocoding.UsCensusBureau/UsCensusBureauGeocoder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;

namespace Geocoding.UsCensusBureau
{
/// <summary>
/// refs:
/// - https://geocoding.geo.census.gov/
/// - https://geocoding.geo.census.gov/geocoder/Geocoding_Services_API.pdf
/// </summary>
public class UsCensusBureauGeocoder : IGeocoder
{
private readonly int _benchmark;
private readonly string _format;
private readonly HttpClient _client;

public UsCensusBureauGeocoder(int benchmark = 4, string format = "json")
{
_benchmark = benchmark;
_format = format;
_client = new HttpClient { BaseAddress = new Uri(UsCensusBureauConstants.BaseUrl) };
}

public async Task<IEnumerable<Address>> GeocodeAsync(string address, CancellationToken cancellationToken = default(CancellationToken))
{
// Build Query String
var sb = new StringBuilder(UsCensusBureauConstants.OneLineAddressPath);
sb.Append("address=").Append(WebUtility.UrlEncode(address))
.Append("&benchmark=").Append(_benchmark)
.Append("&format=").Append(_format);

// Get Request
var response = await _client.GetAsync(sb.ToString(), cancellationToken);
var content = await response.Content.ReadAsStringAsync();

// Read Result
return GetAddresses(content);
}

public async Task<IEnumerable<Address>> GeocodeAsync(string street, string city, string state, string postalCode, string country, CancellationToken cancellationToken = default(CancellationToken))
{
// Build Query String
var sb = new StringBuilder(UsCensusBureauConstants.AddressPath);
sb.Append("street=").Append(WebUtility.UrlEncode(street))
.Append("&city=").Append(WebUtility.UrlEncode(city))
.Append("&state=").Append(WebUtility.UrlEncode(state))
.Append("&zip=").Append(WebUtility.UrlEncode(postalCode))
.Append("&benchmark=").Append(_benchmark)
.Append("&format=").Append(_format);

// Get Request
var response = await _client.GetAsync(sb.ToString(), cancellationToken);
var content = await response.Content.ReadAsStringAsync();

// Read Result
return GetAddresses(content);
}

public Task<IEnumerable<Address>> ReverseGeocodeAsync(Location location, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotSupportedException();
}

public Task<IEnumerable<Address>> ReverseGeocodeAsync(double latitude, double longitude, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotSupportedException();
}

private static IEnumerable<UsCensusBureauAddress> GetAddresses(string response)
{
var json = JObject.Parse(response);

var errors = json[UsCensusBureauConstants.ErrorsKey];
if (errors != null)
return new UsCensusBureauAddress[] {};

var result = json[UsCensusBureauConstants.ResultKey];
return result[UsCensusBureauConstants.AddressMatchesKey]
.Select(match =>
{
var formatted = match[UsCensusBureauConstants.MatchedAddressKey].ToString();
var coordinates = match[UsCensusBureauConstants.CoordinatesKey];
var x = double.Parse(coordinates[UsCensusBureauConstants.XKey].ToString());
var y = double.Parse(coordinates[UsCensusBureauConstants.YKey].ToString());

return new UsCensusBureauAddress(formatted, new Location(y, x));
})
.ToArray();
}
}
}
9 changes: 3 additions & 6 deletions test/Geocoding.Tests/GeocoderTest.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
using Xunit.Extensions;

namespace Geocoding.Tests
{
public abstract class GeocoderTest
{
readonly IGeocoder geocoder;
protected readonly IGeocoder geocoder;
protected readonly SettingsFixture settings;

public GeocoderTest(SettingsFixture settings)
Expand Down Expand Up @@ -106,4 +103,4 @@ public virtual async Task CanGeocodeInvalidZipCodes(string address)
Assert.NotEmpty(addresses);
}
}
}
}
1 change: 1 addition & 0 deletions test/Geocoding.Tests/Geocoding.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<ProjectReference Include="..\..\src\Geocoding.Here\Geocoding.Here.csproj" />
<ProjectReference Include="..\..\src\Geocoding.MapQuest\Geocoding.MapQuest.csproj" />
<ProjectReference Include="..\..\src\Geocoding.Microsoft\Geocoding.Microsoft.csproj" />
<ProjectReference Include="..\..\src\Geocoding.UsCensusBureau\Geocoding.UsCensusBureau.csproj" />
<ProjectReference Include="..\..\src\Geocoding.Yahoo\Geocoding.Yahoo.csproj" />
</ItemGroup>

Expand Down
67 changes: 67 additions & 0 deletions test/Geocoding.Tests/UsCensusBureauTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Geocoding.UsCensusBureau;
using Xunit;

namespace Geocoding.Tests
{
[Collection("Settings")]
public class UsCensusBureauTest : GeocoderTest
{
public UsCensusBureauTest(SettingsFixture settings) : base(settings)
{
}

protected override IGeocoder CreateGeocoder()
{
return new UsCensusBureauGeocoder();
}

[Theory(Skip = "not supported - us addresses only")]
public override Task CanGeocodeAddressUnderDifferentCultures(string cultureName)
{
return Task.CompletedTask;
}

[Theory(Skip = "not supported - reverse geocode")]
public override Task CanReverseGeocodeAddressUnderDifferentCultures(string cultureName)
{
return Task.CompletedTask;
}

[Theory(Skip = "using different input with CanGeocodeWithSpecialCharacters2")]
public override Task CanGeocodeWithSpecialCharacters(string address)
{
return Task.CompletedTask;
}

[Theory]
[InlineData("12110 CLAYTON ROAD TOWN & COUNTRY,SAINT LOUIS,MO,63131,US")]
public async Task CanGeocodeWithSpecialCharacters2(string address)
{
Address[] addresses = (await geocoder.GeocodeAsync(address)).ToArray();

//asserting no exceptions are thrown and that we get something
Assert.NotEmpty(addresses);
}

[Theory(Skip = "not supported - exact addresses only")]
public override Task CanHandleStreetIntersectionsByAmpersand(string address)
{
return Task.CompletedTask;
}

[Fact(Skip = "not supported - reverse geocode")]
public override Task CanReverseGeocodeAsync()
{
return Task.CompletedTask;
}

[Theory(Skip = "not supported")]
public override Task CanGeocodeInvalidZipCodes(string address)
{
return Task.CompletedTask;
}
}
}