I'm trying to implement a SoapExtension for log purposes (print the xml soap request) on an .NET 2.0 client application (not ASP.NET).
I first tried a simple console application just to check and I'm not able to see that the extension is called.
The simple code is just two lines:
System.Net.WebRequest request = System.Net.WebRequest.Create("http://www.ynet.com");
WebResponse response = request.GetResponse();
and my config file is the following:
What I'm doing wrong? are the extension usable only in ASP.NET?
Thanks
You must have class e.g.:"YourExtension" derived from "SoapExtension" class and attribute class e.g. "YourExtensionAttribute" derived from "SoapExtensionAttribute" there you overide "Type" property:
public override Type ExtensionType
{
get { return typeof(YourExtension); }
}
and put SoapExtensionAttribute to your webservice method
Related
I am developing a rest application.
Some endpoints require a custom header parameter, not related to authorisation. I created a custom annotation using jax-rs NameBinding. Here is an usage example:
#GET
#RequiresBankHeader
public int get(
#HeaderParam("bank")
#Parameter(ref = "#/components/parameters/banks")
String bank) {
return someService.getSomeInformation();
}
There is a provider that intercepts this call and do some routine using the information in the header parameter.
The problem is that I have to repeat '#HeaderParam("bank") #Parameter(ref = "#/components/parameters/banks") String bank' everywhere, just so it appears in Swagger, even though the service classes do not need it. I was able to at least reuse the parameter definition with ref = "#/components/parameters/banks", and declaring it in the OpenAPI.yml file, that Quarkus merges with generated code very nicely.
But I also want to create and interceptor to dynamically add this do the OpenApi definition whenever RequiresBankHeader annotation is present.
Is there a way to do it?
I dont think you can use interceptors to modify the generated Openapi schema output.
If all methods on a given endpoint require some parameter, you can specify it on class level like so:
#Path("/someendpoint")
public class MyEndpoint {
#HeaderParam("bank")
#Parameter(name = "bank")
String bank;
#GET
public Response getAll() {return Response.ok().build()}
#GET
#Path("{id}")
public Response someMethod(#PathParam("id") String id) {return Response.ok().build();}
}
As mentioned by Roberto Cortez, the MP OpenAPI spec provides a programmatic way to contribute metadata to the openapi.yml file.
It is not possible to detect an annotation in the JAX-RS endpoint definition, but it was good enough to automate what I needed. Since all methods that had the RequiresBankHeader return the same Schema, I was able to hack it like this:
public class OpenApiConfigurator implements OASFilter {
#Override
public Operation filterOperation(Operation operation) {
operation.getResponses().getAPIResponses().values().stream().
map(APIResponse::getContent).
filter(Objects::nonNull).
map(Content::getMediaTypes).
flatMap(mediaTypes -> mediaTypes.values().stream()).
map(MediaType::getSchema).
filter(Objects::nonNull).
map(Schema::getRef).
filter(Objects::nonNull).
filter(ref -> ref.contains("the common response schema")).
findAny().
ifPresent(schema -> {
ParameterImpl parameter = new ParameterImpl();
parameter.setRef("#/components/parameters/banks");
operation.addParameter(parameter);
});
return operation;
}
OpenApiConfigurator should be configure in the application properties, using mp.openapi.filter=com.yourcompany.OpenApiConfigurator
My GET method WORKS fine when I use the url logged in as SuperUser like this(I get the name of the first user pulled from the DB):
http://localhost/DesktopModules/AAAA_MyChatServer/API/ChatApi/GetMessage
But I cannot access the POST method in the same controller either using AJAX from view or just by entering the url (post method doesnt get hit/found):
http://localhost/DesktopModules/AAAA_MyChatServer/API/ChatApi/SendMessage
And also this fails as well:
$('#sendChat').click(function (e) {
e.preventDefault();
var user = '#Model.CurrentUserInfo.DisplayName';
var message = $('#chatBoxReplyArea').val();
var url = '/DesktopModules/AAAA_MyChatServer/API/ChatApi/SendMessage';
$.post(url, { user: user, message: message }, function (data) {
}).done(function () {
});
});
The Error message is:
<Error>
<Message>
No HTTP resource was found that matches the request URI 'http://localhost/DesktopModules/AAAA_MyChatServer/API/ChatApi/SendMessage'.
</Message>
<MessageDetail>
No action was found on the controller 'ChatApi' that matches the name 'SendMessage'.
</MessageDetail>
</Error>
And sometimes:
"The controller does not support GET method"
even though I do have both a GET and a POST there and the GET works. What am I missing?
I have made a routing class in my DNN project:
using DotNetNuke.Web.Api;
namespace AAAA.MyChatServer
{
public class RouteMapper : IServiceRouteMapper
{
public void RegisterRoutes(IMapRoute mapRouteManager)
{
mapRouteManager.MapHttpRoute("MyChatServer", "default", "{controller}/{action}", new[] { "AAAA.MyChatServer.Services" });
}
}
}
I added a DNN Api Controller in folder Services of my project named AAAA.MyChatServer:
using DotNetNuke.Web.Api;
using System.Linq;
using System.Net.Http;
using System.Web.Http;
namespace AAAA.MyChatServer.Services
{
[DnnAuthorize(StaticRoles = "SuperUser")]
public class ChatApiController : DnnApiController
{
[HttpGet]
public HttpResponseMessage GetMessage()
{
ChatServerManager csm = new ChatServerManager();
var users = csm.GetAllUsers();
var user = users.FirstOrDefault().Name;
return Request.CreateResponse(System.Net.HttpStatusCode.OK, user);
}
[System.Web.Http.HttpPost]
public HttpResponseMessage SendMessage(string toUser, string message)
{
return Request.CreateResponse(System.Net.HttpStatusCode.OK);
}
}
}
There are two ways to call a POST method in a DNN WebAPI: with parameters and with an object. If you use parameters, as you have in your SendMessage method, those parameter values need to be delivered via the Query String.
On the other hand, creating an object and sending that with your call to the WebAPI method can handle a great many more scenarios and is arguably a better way of handling any POST method (as it hides those values from prying eyes, making the call more difficult to counterfeit). To handle this, you can remove the parameters from your SendMessage method and instead interrogate the HttpContext.Current.Request object within your method. The object you created { user: user, message: message } will be nestled in there somewhere.
As it is written in your example, your object was sailing past your parameters like two ships in the night.
I've only just figured this out myself, and I don't have all the understanding I need yet, but hopefully this will help you along your way. Here are some articles I referenced in my quest to use cURL to upload a file to my DNN WebAPI:
https://www.dnnsoftware.com/community-blog/cid/134676/getting-started-with-dotnetnuke-services-framework
https://www.dnnsoftware.com/community-blog/cid/144400/webapi-tips
How To Accept a File POST
https://forums.asp.net/t/2104884.aspx?Uploading+a+file+using+webapi+C+
https://talkdotnet.wordpress.com/2014/03/18/dotnetnuke-webapi-helloworld-example-part-one/comment-page-1/
http://dnnmodule.com/Article/ArticleDetail/tabid/111/ArticleId/511/Dotnetnuke-7-0-WebAPI-Tips.aspx
How to post file using Curl in WebApi in Asp.Net MVC
Good luck!
Your Web Api for SendMessage contain 2 parameter, so it should POST in query string :
http://localhost/DesktopModules/AAAA_MyChatServer/API/ChatApi/SendMessage?touser=john&message=hello
if you want to POST it using data of object, you need to make the Web Service parameter as object model
Also your javascript parameter is different from the Web Service, as it use "toUser"
As per their documentation from link https://docs.helloworks.com/v3/reference#callbacks
"With the HelloWorks API you can use callbacks to be notified about certain events. Currently we support a callback to be registered when a step is started, the cancellation of a workflow, and the completion of a workflow.
The callback URL will be called according to the following:
curl -X POST https://your.domain.com/some/path
-H "X-HelloWorks-Signature: {signature}"
-H "Content-Type: application/json"
-d "{payload}
I am not able to figure out how can I handle the callback in ASP.NET MVC 4.0. The callback returns data on JSON format. Once I receive the data, I can format it as per my need and can save to database. But how can I get the data in my controller? Guidance from experts on APIs are highly appreciated. Thanks in advance.
I am not able to figure out how can I handle the callback in ASP.NET MVC 4.0.
You need to have an api controller that accepts POST requests. That api endpoint is then called by the HelloWorks api. The fancy word to describe this mechanism is a Webhook. A nice introduction can be found here.
The very basic would be a controller like
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace MyWebAPI.Controllers
{
public class WebHookController : ApiController
{
// POST: api/webhook
public void Post([FromBody]string value)
{
}
}
}
You will need to register the url https://yourwebsite.domain/api/webhook at the HelloWorks api so it knows where to send the data to.
You probably want to secure this endpoint so others cannot abuse this api. See the docs for some guidance.
For example, in your case you should check that a header named "X-HelloWorks-Signature" is send in the request to the endpoint. The value of that header is a hash that should match the value of a hash of the content you received. To calculate the hash code to match create a hash using the SHA-256 algorithm and base16-encode the result.
There is also documentation from Microsoft on how to create web apis
Peter your guidance worked. I appreciate that. It was straight forward, only the technical jargon are making it intimidating :). Below are the code that worked. I am still to secure it using signature.
[HttpPost]
public ActionResult Callback()
{
string rawBody = GetDocumentContents(Request);
dynamic eventObj = JsonConvert.DeserializeObject(rawBody);
Test newTest = new Test();
newTest.Response = "Bikram-1" + (string)eventObj.type;
var test = db.Tests.Add(newTest);
db.SaveChanges();
return Content("Success!");
}
private string GetDocumentContents(HttpRequestBase Request)
{
string documentContents;
using (Stream receiveStream = Request.InputStream)
{
using (StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8))
{
documentContents = readStream.ReadToEnd();
}
}
return documentContents;
}
My web app is using PKI authentication via a piv card. I grab the user's unique identifier information via HttpClientCertificate.Subject. The problem is that when I am unit testing, mock will not mock this class since it doesn't have a constructor. I tried following the advice on this thread:
How to mock HttpClientCertificate?
but it looks like the way he sets it up is to inject the client certificate through the controller's constructor which I dont' want to do since the controller already has access to the client certificate. I'm assuming thats what he is implying since he is using some type of adapter pattern. Anyone got any better sugguestions?
Why don't you wrap it into your own object?
class MyHttpClientCertificate
{
public MyHttpClientCertificate(HttpClientCertificate foo) { ... }
internal MyHttpClientCertificate() { ... }
}
Your issue is that the code is using the Request object to get the certificate, but that's not easily unit testable.
What I would do is add a function delegate that, by default, will use the Request object to return the HttpClientCertificate, but will allow overriding the implementation.
For the controller, add this:
internal Func<HttpClientCertificate> HttpClientCertificateGetter = () => {
return Request.ClientCertificate;
}
And in your Controller instead of using Request use HttpClientCertificateGetter.
Then in your unit test you mock the certificate and assign it to the getter function, like this:
var certMock = new Mock<HttpClientCertificate>();
HttpClientCertificate clientCertificate = certMock.Object;
requestMock.Setup(b => b.ClientCertificate).Returns(clientCertificate);
certMock.Setup(b => b.Certificate).Returns(new Byte[] { });
controller.HttpClientCertificateGetter = () => {certMock.Object};
I'm starting to learn Json.NET, but I'm having trouble using its serializer. I have a new MVC4 project with a Web.API service:
public class PTE_TestsController : ApiController {
PTE_TestsRepository _repository = new PTE_TestsRepository();
// GET /api/PTE_Tests/5
public HttpResponseMessage<string> Get(int id) {
try {
PTE_Test test = _repository.GetTest(id);
return new HttpResponseMessage<string>(JsonConvert.SerializeObject(test));
} catch {
return new HttpResponseMessage<string>(HttpStatusCode.NotFound);
}
}
}
JsonConvert.SerializeObject() works as expected and returns a string. My Web.API controller returns that as part of an HttpResponseMessage. The end result, when viewed in Fiddler, is not JSON data, but JSON data being serialized again (I think):
"{\"ID\":1,\"Name\":\"Talar Tilt\",\"TagID\":1,\"PracticeID\":1,
\"SpecificAreaID\":1,\"TypeID\":1,\"VideoID\":1,\"PicID\":1}"
Does someone know how to turn off the default serializer so I can use Json.NET directly? By the way, I'm not using the default serializer because I can't figure out how to make it work with complex objects (PTE_Test will eventually contain members of type List).
Alternately, it will also solve my problem if someone can explain how to use the default serializer with complex objects. MSDN's explanation didn't help me.
Rick Strahl has a blog on that here with a code that works.
As others have pointed out, you need to create a formatter and replace the DataContractSerializer with the JSON.NET serializer. Although, if you're not in a rush for JSON.NET specifically, rumor has it that next beta/rc is going to have support for JSON.NET built in.
Conceptually, however, you're missing part of the magic of WebAPI. With WebAPI you return your object in it's native state (or IQueryable if you want OData support). After your function call finishes the Formatter's take over and convert it into the proper shape based on the client request.
So in your original code, you converted PTE_Test into a JSON string and returned it, at which point the JSON Formatter kicked in and serialized the string. I modified your code as follows:
public class PTE_TestsController : ApiController {
PTE_TestsRepository _repository = new PTE_TestsRepository();
public HttpResponseMessage<PTE_Test> Get(int id) {
try {
PTE_Test test = _repository.GetTest(id);
return new HttpResponseMessage(test);
} catch {
return new HttpResponseMessage<string>(HttpStatusCode.NotFound);
}
}
}
Notice how your function returns PTE_Test instead of string. Assuming the request came in with a request header of Accept = application/json then the JSON formatter will be invoked. If the request had a header of : Accept = text/xml the XML formatter is invoked.
There's a decent article on the topic here. If you're a visual learner, Scott Gu shows some examples using fiddler in this video, starting around 37 minutes. Pedro Reys digs a little deeper into content negotiation here.
The way to do this is to use formatters.
Check out: https://github.com/WebApiContrib/WebAPIContrib/tree/master/src/WebApiContrib.Formatting.JsonNet.
Json.NET support will be in the RC release of Web API.