I am trying to develop a PATCH endpoint in my web api application. In the update model I have attributes for required data and some custom attributes. Since I found out that the attribute validation is not executed as expected in PATCH endpoints I needed to trigger the validation with a method as follows
private void Validate(object model, Type type)
{
var validator = Configuration.Services.GetBodyModelValidator();
var metadataProvider = Configuration.Services.GetModelMetadataProvider();
HttpActionContext actionContext = new HttpActionContext(
ControllerContext, Request.GetActionDescriptor());
if (!validator.Validate(model, type, metadataProvider, actionContext, String.Empty))
{
throw new HttpResponseException(Request.CreateErrorResponse(
HttpStatusCode.BadRequest, actionContext.ModelState));
}
}
This logic works fine for me. The problem is that when I try to write a unit test for the PATCH endpoint the tests fails because Request.GetActionDescriptor() returns null. Maybe I need to set up my controller in a different way. Any ideas? Maybe I need to setup the Request object somehow
Related
This question already has answers here:
Mock HttpContext.Current in Test Init Method
(4 answers)
Closed 6 years ago.
I have Web Api controller Action method I am trying to unit test. I have one custom filter which runs before that action controller.
I have question regarding HttpContext.Current.User.Identity.Name that I am using inside my custom action filter.
It works nicely when I send my http post request from web client.
But, when I send http post request from my unit test than HttpContext.Current always complain for null
Don't understand where and what is wrong.
Anybody can please explain it?
Please note that I have seen answers at here but not sure where I need to add that code in my case.
Unit testing is not the same as calling your api through a web client.
When you are using a web client, you api is running in the context of you web server (IIS, for example) and the web server will provide the system with che "current" HttpContext.
If you call you code plain and simple from a unit test method you're not running in the context of a web server, but you're calling it simply as a method of a class. Obviously you can do it, but you need to "mock" (of fake, if you want) the current HttpContext to simulate you're running in a real web server.
Check this SO answer for the details on how to do it.
BTW, this is not the case when you run integration tests (means calling the real API throught a web client and just check the input-output results): in that case you are running your real code in a real context and everything will work fine.
HttpContext.Current is not set in a self hosted scenario like in your test.
You can however create a wrapper around HttpContext.Current and populate it before you run your test. Like this:
public static class CurrentHttpContext
{
public static Func<HttpContextBase> Instance = () => new HttpContextWrapper(HttpContext.Current);
}
And then somewhere in your test where you set up your HttpSelfHostServer, you populate the CurrentHttpContext.Instance. For example with FakeItEasy (https://github.com/FakeItEasy/FakeItEasy):
var context = A.Fake<HttpContextBase>();
CurrentHttpContext.Instance = () => context;
Then you can access CurrentHttpContext.Instance instead of HttpContext.Current in your filters:
public class MyAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var context = CurrentHttpContext.Instance();
// stuff
}
}
I dont want to pass the session Id every time to get or update the information using SOAP. Because for that I would have to run a separate request every time to get the session ID. Isn't it possible to provide username/pass everytime before running a SOAP or just once per session??
Thanks,
Yep this is doable, but it will be some work to do:
You should create an custom Server Handler by overriding the default one.
Create a Handler.php file in -magentopath/app/code/local/Company/Api/Model/Server/Handler.php
Override the call method.
class Company_Api_Model_Server_Handler
extends Mage_Api_Model_Server_Handler
{
public function call($sessionId, $apiPath, $args = array())
{
$sessionId = $this->login($args['username'], $args['password']);
parent::call($sessionId, $apiPath, $args);
}
}
In this way you cand send null for $sessionId, and make an login with the needed credential on the server side.
I do not suggest this approach at all, but as a workaround it could work.
I've read a lot about switching between multiple datasource on runtime, but as far as I understand they're already defined datasources. I'm not quite sure on how can I just asign the datasources properties on runtime from a webservice call.
I don't need to switch between datasources, just need to create only one datasource with conection data coming from a webservice.
Is there a way to retrieve these parameters from the webservice and create the datasource from that?
The policy here is to retrieve the datasource parameters from a webservice for all the projects, that way the connection data is not inside a file nor into the code, and is only manipulated by DBAs from a global security aplication.
I tried to call the web service in the same datasource file, but it didn't work.
Info:
Web service is a Soap Web service
Grails: 1.3.9
Regards.
I think that you can create a BeanPostProcessor that take care of calling your webservice and changing the settings of your dataSource.
Probably you will need to delay the session factory creation, making sure Grails won't try to use your dataSource before you have all setted up correctly.
The BeanPostProcessor will looks like:
class WebserviceDataSourceBeanPostProcessor implements BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean
}
Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof DataSource){
def info = //call webservice here...
bean.username = info.username
bean.password = info.password
bean.url = info.url
//checkout more setters in: http://commons.apache.org/proper/commons-dbcp/apidocs/org/apache/commons/dbcp/BasicDataSource.html
}
return bean
}
}
And make sure you declared this Spring Bean in resources.groovy
beans = {
webserviceDataSourceBeanPostProcessor(WebserviceDataSourceBeanPostProcessor)
}
If you will have more than one project with this same config comming from a webservice you may think in the possibility of a plugin for this, reusing your code.
I’ve got a Web API that I’ve added [Authorize] attributes to, which means that the unit tests I had previously now fail due to them being unauthorised. Here’s a sample of a basic test along with an initialiser method:
[TestInitialize]
public void CreateServer() {
var config = new HttpConfiguration();
WebApiConfig.Configure(config); // Create the routes
var server = new HttpServer(config);
this.client = new HttpClient(server);
}
[TestMethod]
public void MyThings_GET_Returns_All_MyThings() {
var response = this.client.GetAsync("http://localhost/api/1.0/mythings").Result;
var mythings = response.Content.ReadAsAsync<IEnumerable<MyThing>>().Result;
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.AreEqual(4, mythings.Count());
}
What I’m wondering is if there’s any way that I can either make my test log in so that it passes the authorization filter, or if there’s any way that I can pass as ASPXAUTH cookie along with the HttpClient request? Or another way of passing authorization that I haven’t thought of?
Nothing I’ve tried seems to work and I’m struggling to find any helpful info anywhere.
Thanks in advance.
What does your Authorize attribute do when it performs the authorization check? There are quite a few options that come to mind:
Have the authorize filter support multiple means of getting the "authorization token" that it requires (e.g. through an HTTP header or a querystring parameter, etc)
Right after your test initialization, clear out the filter from the configuration (so that it is not called at all). If you choose to go this route then you may wish to pop in a new filter that sets any authorization values that might be used further along the pipeline
If you are using dependency injection, move the "authorization check" into some sort of IAuthorize location that can be updated in your configuration
I would also recommend using RestSharp for making queries to your endpoints as it does a very good job of specifying headers, parameters, etc.
I decided that the way I was going about the problem was fundamentally wrong. Using cookie-based authorisation with Web API is just not a good idea, so I’ve decided to get rid of the authorize attributes and perform API-Key-based authentication instead. This makes it easier to test as I can just pass the correct API key in the request, but also means that I’m not relying on cookies for authorisation.
I'm behind ISA Server Proxy and I need to call a web service. Given its wsdl I've created proxies (using Add Service Reference command) and have tried to call the service, but it raised an exception telling me that proxy authorization is required. After some research I've found a solution to my problem
var webproxy = new WebProxy(new Uri("http://<address>:<port>").ToString(), true, new string[]
{
})
{
Credentials = networkCredentials,
BypassProxyOnLocal = false
};
WebRequest.DefaultWebProxy = webproxy;
After this piece of code I'm able to call web service. But as I've read here by default DefaultWebProxy uses the same settings as set in IE. However WebRequest.DefaultWebProxy.Credentials is null and I'm unable to pass thru the proxy. Why?
I've was also same boat. The last answer on this post helped me.
How do I determine (elegantly) if proxy authentication is required in C# winforms app
Especially.
//HACK: add proxy
IWebProxy proxy = WebRequest.GetSystemWebProxy();
proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
req.Proxy = proxy;
req.PreAuthenticate = true;
//HACK: end add proxy