How to expose simple web service using Basic Authentication in ASP.NET - c#

I maintain an ASP.NET Web API project which supports a simple REST end point for clients to post XML data to our server. This site is setup to support BasicAuthentication and works very well. All of our security checks are done at the network firewall and on the machine itself using custom Windows User accounts. Recently, one of our clients requires that we support a SOAP end point to receive the XML data as well.
My thought was to simply add a new WebService (Blah.svc) with supporting interface having the required [ServiceContract] and [OperationContract] attributes to my interface. I had hoped that I could simply expose the URL to our client and it would "just work". I am able to hit the end point, but this service is not able to extract the user name.
Here is my sample code:
public string CreateWorkItem(string xml)
{
var userName = HttpContext.Current.User.Identity.Name;
if (string.IsNullOrEmpty(userName))
userName = "NO USER NAME";
var elem = XElement.Parse(xml);
return $"Hello [{userName}]! You sent [{elem.Value}].";
}
Here are my results:
I've scoured the web to try and find out how to get access to the BasicAuthentication details in a Soap message, but I'm not having any luck. All the examples that I'm finding require that I create a new WCF project and expose it with a lot of web.config settings, or the examples are ~5 years old using older techniques.
I'd like this service to simply publish with my WebAPI project using the Publish... option inside Visual Studio. Unfortunately, I've not found a common denominator to make it work. I'm sure I'm missing something, and I hope someone can help.
Any help would be greatly appreciated!

Check this link out: WCF Services and ASP.NET
In short you need to enable ASP.NET Compatibility in your WCF service.
However, you may want to look into using OperationContext.Current.ServiceSecurityContext.*

The fact that it is HttpContext.Current.User.Identity.Name is returning null means either:
User is null; or
User is Anonymous
I have a few ideas to help resolve the issue.
1. Your User.Name is actually null
You might want to debug by grabbing HttpContext.Current.User and see if it's correct.
2. Go direct: get the cookie via a parameter
Try and pass the HttpContext as a parameter so you can grab the cookie?
public string CreateWorkItem(HttpContext context, string xml)
{
var username = context.Current.User.Identity.Name;
...
}
3. Your configurations are not setup properly
The alternative is that maybe your web.config or Global.asax is not setup to properly.

Related

How to work with Visual Studio 2017 generated restful api from swagger docs

So I am working with Visual Studio 2017 Enterprise, and I noticed the other day that you can right click and do file add restful api client. So I went out and generated the .json file for my restful service. My Visual Studio generated a bunch of classes and files. However, I don't understand how to work with these classes?
What is an example code of creating an object to call my restful backend methods?
I thought perhaps this was the object I need to work with, but then what are the ServiceClientCredentials if they cannot be null?
public AngularDemoComplete(ServiceClientCredentials credentials, params DelegatingHandler[] handlers) : this(handlers)
{
if (credentials == null)
{
throw new ArgumentNullException("credentials");
}
this.Credentials = credentials;
if (this.Credentials != null)
{
this.Credentials.InitializeServiceClient(this);
}
}
I am still trying to work out a complete solution, but I did manage to get this working by passing in these parameters:
(new TokenCredentials("<bearer token>"), null)
Unfortunately I don't really understand what this means at the moment. I found this in a post about working with autorest clients, which seems to generate similar code: https://dzimchuk.net/generating-clients-for-your-apis-with-autorest/
I am continuing to work this out and will update this as I learn more.
Any updates from you would be appreciated.
Cheers
Additionally, I got it working by commenting out the null check on the credentials parameter. But that probably is not advisable. It is just interesting to note that it can work without the credentials if there is no authentication required.
UPDATE: I have found there are 2 other types of credentials available that appear to be a bit more self explanatory:
BasicAuthenticationCredentials
CertificateCredentials
Apparently with the TokenCredentials you would need to obtain the token from the server prior to this step. This might be needed if using OAuth.
As I don't need authentication initially, I am just going to use the BasicAuthenticationCredentials without setting the UserName and Password properties.
I was surprised there were not more examples of how to use the generated code, created by https://github.com/Azure/AutoRest so I thought it worthwhile to add something here.
+10 for #Keiran for referring to BasicAuthenticationCredentials, which as it turns out, extends BasicAuthenticationCredentials and therefore, can be used as follows:
BasicAuthenticationCredentials credentials = new BasicAuthenticationCredentials();
credentials.UserName = "joe#bloggs.com.au";
credentials.Password = "passwordvalue";
System.Uri baseUri = new System.Uri("https://api.something.com.au/v0.1/");
APIClassName client = new APIClassName(baseUri, credentials);
APIClassNameSpace.Models.SomeResponse someResponse = client.GetSomething(requestHeaderParameter1, pathParameter1);
Visual Studio 2019 currently produces a Models folder containing all of the classes referenced by the swagger file. It also produces three other classes, e.g. IAPIClassName, APIClassName, APIClassNameExtensions. Use APIClassName to instantiate the client - the operations specified in the swagger file will be available with auto-completion. I didn't dig too deeply but the class prefixed with I looked like an interface definition and the class suffixed with extensions looked lie the implementation of the interface. My example illustrated the use of a request header parameter and a path parameter although the implementation of that handling is generated using the details in the swagger file.
I must mention How to handle both a single item and an array for the same property using JSON.net as part of this discussion. Anyone dealing with the JSON and generated code for should know about this!

CRM 2013 Get CRM URL via Custom Workflow

I have a requirement for getting a CRM URL via a custom workflow to use in the next step which is to send an email. The reason for this is to differentiate to users which server this email has come from (UAT/Live).
I have been trying to use HTTPContext route as advised from this site https://social.microsoft.com/Forums/en-US/31ff567d-65ea-4385-a764-68a2121ae8c0/ms-crm-2011-get-path-of-crm-server-url-in-plugin?forum=crmdevelopment but the result I get back is useless as I am I am only receiving an "/" back.
Does anyone know what to do from this point or why this may not be working?
This can't be accomplished, in a supported manner, without creating a connection to the CRM Discovery Service, which requires that you supply credentials. The organization service, available in the workflow does not have a method for discovering the organization's URL.
You have two options:
1) Pass it to the workflow as a parameter using the InputParameter code attribute on your CodeActivity.
2) Create (if you don't already have one) a configuration entity to store the URL and retrieve it in your code.
If you don't really need the URL (i.e., you are not creating a link) then you could just query the Organization entity for the Name attribute. That will give you the Organization's name - which would be the only unique part of the URL. This would allow you to indicate to the user if the Email was coming from UAT or Prod.
I ended up coming up with a solution by using the environment.machinename to pull through the server name. From there i could determine which production server the workflow had been run through and passed a string containing, dev, uat or live to the output to use in my activity emails.
Be aware i had to register the workflow without it being in sandbox mode. Hope this helps somebody in the future.
This was an extremely old question but I came across it while attempting to do something similar.
I found that there is a RetrieveCurrentOrganizationRequest request which was introduced in v9. This will work in sandboxed plugins.
You can use this to retrieve the endpoint urls like so
var currentOrg = base.OrgService.Execute(
new RetrieveCurrentOrganizationRequest()
) as RetrieveCurrentOrganizationResponse;
var url = currentOrg.Detail.Endpoints
.Where(e => e.Key == EndpointType.WebApplication)
.FirstOrDefault()
.Value;
More information here: RetrieveCurrentOrganizationRequest
When I used it, I found that there are 3 available URLs in the Endpoints collection:
Web Application
Organization Data Service
Organization Service
Relevant to CRM 2013 (which the OP was using at the time), there is also the RetrieveOrganizationRequest class which does the same as above; however you have to specify the Organization (and some other information)

C# Web Service client that will fail if WSDL is not available or invalid

My client hosts a few web services and has ASP.NET Web pages that will demo the web service and acts as a quick check to verify that the web service is up by the client. The problem is that the WSDL might be missing or invalid, but the Web Service will still work.
What I'd like to add to the ASP.NET web service client is a way to verify that the WSDL is there and valid, but have no idea where to start. Any suggestions would be greatly appreciated! Code behind is C#
I'm not entiery sure what you mean with verify that the WSDL is valid. Only thing I can suggest is, use an HttpWebRequest on the specific URI and see what response you get then either throw an exception based on specific status codes like 404 for example or handle it in a different way.
You can fetch the status code value
var request = (HttpWebRequest) WebRequest.Create("http://example.com/service.wsdl");
using (var r = (HttpWebResponse) request.GetResponse())
{
var result = r.StatusCode.ToString() == 200.ToString() ? "Success" : "Service not found";
Debug.WriteLine(result);
}
Hope this helps, goodluck.
Edit: if you know what services you're going to be testing you can simply add them as service reference in your client project and try to do an RPC on the service methods to see if it's available. Pictures below show to add a service reference.
Your scenario doesn't completely make sense. You could make a request to the service WSDL endpoint, http://something/service.asmx?wsdl and you could confirm that what comes back is a WSDL file. You could even validate it against the WSDL and XSD schemas.
This wouldn't tell you whether it was a WSDL that represented the service. It could conceivably be a WSDL for some totally different service.
Maybe more importantly, have you had problems where the service was available but the WSDL was not? In that case, rather than create diagnostics, I recommend that you fix the problem.

Web services to validate the canadian address through purolator webservice

Hey I am trying to use Purolator Web services to validate the address.
I already included web services in my project and have all credential to communicate but I don't know how to validate through web services and it's my first time that I am using web services please help
I am using C#
I have three input field to asp.net to validate
city
Postcode and
province
If someone can give me details info how to this validation through web service I will really appreciate their help.
Please give some sample code how can I do this
already included reference
using com.purolator.devwebservices;
com.purolator.devwebservices.ValidateCityPostalCodeZipRequestContainer;
This is how it show in their documentation.
I like to upload the picture to show you the web service request and response diagram but I don't have privileges
ValidateCityPostalCodeZipRequestContainer
ValidateCity PostalCodeZipRequest
tns:RequestContainer (extension)
tns:Addresses SenderA ddress - ShortAddress[]
tns:ArrayOfShortAddress
tns:ShortAddress
tns:ShortAddress
tns:City City -string
tns:Province Province - string
tns:Country C ountry - string
tns:PostalCode P ostalC ode; - string
In order to call the webservice, you first have to add a web reference, which you already did, now you need to instantiate the object of proxy class which from your post i believe is ValidateCityPostalCodeZipRequestContainer and call the RequestContainer method of object with required parameter to validate the address.
* Answer above is based on my assumptions becuase I don't have any information about the webservice. If you can post WSDL then I can give a precise answer.
Between, according to Purolator's website there are number of sample available here: https://eship.purolator.com/SITE/en/content/developmentprocess/websservicesprogram.aspx
May be you can find one using asp.net
And by the way there is a nice tutorial given here for consuming webservices in asp.net: Calling Web Service using ASP.NET.

Custom SharePoint 2010 WCF Service - How to set MaxReceivedMessageSize parameter

I have developped a custom WCF Web Service within a SharePoint 2010 Visual Studio empty project.
My web service is working well. The problem is related to the size of the request I can send to this web service. I have realized that is something around 300Kb. If I go bigger than that, the service/client is sending me an exception.
I've looked around on the web and see that the MaxReceivedMessageSize setting may be my solution. I've tried using a FeatureActivated method to set this information using this kind of request:
// increase maximum size of requests to this web service: http://msdn.microsoft.com/en-us/library/ff599489.aspx
SPWebService contentService = SPWebService.ContentService;
contentService.ClientRequestServiceSettings.MaxReceivedMessageSize = -1;
SPWcfServiceSettings csomWcfSettings = new SPWcfServiceSettings();
csomWcfSettings.MaxReceivedMessageSize = 10485760; // 10MB
contentService.WcfServiceSettings["PT-SP-P2S-DocumentCreator.svc"] = csomWcfSettings;
contentService.Update(); // access denied thrown here!
With that code, I have an Access denied (I'm actually the Site Collection Administrator).
I also know that this parameter may be set in the app.config of web service host but, in SharePoint, where to I need to change this parameter.
I think you should make this change in the web.config file of the Web Application in which the feature is activated. SharePoint provides APIs to make web.config changes. In fact, using APIs to make changes to your web.config is preferred option because SharePoint uses Timer Job and makes same updates to all Web Front End servers in your environment. There are 2 ways to make changes to web.config as described here:
http://msdn.microsoft.com/en-us/library/ms460914.aspx
In your case, since you want to make the change only when your feature is activated, you would take the API approach as documented here: http://msdn.microsoft.com/en-us/library/bb861909.aspx

Categories