0

I've got a web application created with ASP.NET and a windows native client program written in c#.
The windows native program needs to send and fetch data from the ASP.NET web application.
I guess in the web application I'll need a controller for the external calls. And in the client Software I somehow Need to call them.

  • Is there a way to achieve calls with complex data types (lists of classes) as parameters?
  • How do I secure the calls from the client? Simple http-logon?

for example I'd like to transfer an instance of this class to or from the ASP.NET web application:

public class Address
{
  public String Street {get;set;}
  public String City {get;set;}
}
public class CustomerInformation
{
 public String No {get;set;}
 public String Name {get;set;}
 public List<Address> Addresses {get;set;}
}

Of course the Windows client is running somewhere local while the ASP.NET Service is running in the web.

Sam
  • 28,421
  • 49
  • 167
  • 247
  • Can you use HttpClient? If so, maybe this will help? http://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client – BattlFrog Aug 27 '15 at 14:50

2 Answers2

1

I would add API controller and put some methods there. For instance

// Addresses API 
public class AddressController : ApiController
{
    private readonly IRepository<Address> _repository;

    public AddressController(IRepository<Address> repository)
    {
        _repository = repository;
    }

    [BasicAuthorize]
    public IList<Address> GetList()
    {
        return _repository.GetAll();
    }
}

// Constomer information API
public class CustomerInformationController : ApiController
{
    private readonly IRepository<CustomerInformation> _repository;

    public CustomerInformationController(IRepository<CustomerInformation> repository)
    {
        _repository = repository;
    }

    [BasicAuthorize]
    public IList<CustomerInformation> GetList()
    {
        return _repository.GetAll();
    }
}

To secure those methods you can use Basic authentication. This means that you can add authorization header for each request:

For example how it looks for user "myuser" with password "test"

Authorization: basic bXl1c2VyOnRlc3Q=

// Custom attribute for Basic authentication
public class BasicAuthorizeAttribute : System.Web.Http.AuthorizeAttribute
{
    private readonly string[] _permissionNames;

    public BasicAuthorizeAttribute()
    {
    }

    public BasicAuthorizeAttribute(params string[] permissionNames)
    {
        _permissionNames = permissionNames;
    }

    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        // check if user has been already authorized
        if (base.IsAuthorized(actionContext))
            return true;

        var user = AuthenticateUser(actionContext);

        // here you can check roles and permissions

        return user != null;
    }

    private IUser AuthenticateUser(HttpActionContext context)
    {
        var request = context.Request;
        AuthenticationHeaderValue authHeader = request.Headers.Authorization;
        if (authHeader != null)
        {
            // RFC 2617 sec 1.2, "scheme" name is case-insensitive
            if (authHeader.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase) && authHeader.Parameter != null)
                return AuthenticateUser(authHeader.Parameter);
        }
        return null;
    }

    private IUser AuthenticateUser(string credentials)
    {
        try
        {
            // parse values
            var encoding = Encoding.GetEncoding("iso-8859-1");
            credentials = encoding.GetString(Convert.FromBase64String(credentials));

            var credentialsArray = credentials.Split(':');
            var username = credentialsArray[0];
            var password = credentialsArray[1];

            // authentication
            var membershipService = new IMembershipService();
            return membershipService.ValidateUser(username, password);
        }
        catch (Exception)
        {
            // Credentials were not formatted correctly.
            return null;
        }
    }
}

On client side you can use HttpClient to send async request

    public async Task<Address[]> GetAddresses() {
        var client = new HttpClient {BaseAddress = new Uri(_settingsService.GetHost())};
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        var base64 = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "myuser", "test")));
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",base64);

        HttpResponseMessage response = await client.GetAsync("api/addresses");
        if (response.StatusCode != HttpStatusCode.OK)
            throw new Exception(response.ReasonPhrase);

        string content = await response.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<Address[]>(content);
    } 
Evgeny Shmanev
  • 771
  • 6
  • 11
0

Is there a way to achieve calls with complex data types (lists of classes) as parameters?

Yes, The server application as ASP.NET or ASP.NET MVC or (preferably) ASP.NET WEB API can provide services with complex data types. In fact there is no limitation in declaring methods.

How do I secure the calls from the client? Simple http-logon?

There are wide ranage of authentication and authorization mechanism in ASP.NET (MVC, WEB API) which give you opportunity to choose one them.

The data transfers between your client and server via XML or JSON.

The "WebClient" class provides everything that you need to make a call from client to server.

More information:

Community
  • 1
  • 1
Abbas Amiri
  • 3,074
  • 1
  • 23
  • 23