Getting the "no type was found that matches the controller named" error message during Ajax Request - web-services

I've seen a lot of topics about this, but unfortunately I believe that each case is a different case (or most of them), and I really would love some experts opinion about my case in particular since I cannot make my code work even after reading through some of the other topics.
Situation: I am using an Ajax Request call in jQuery to a WebService method I have created in an WebApi project together with a MVC 4 Application.
My WebService controller class looks like the default, like this:
public class AdditionalInfoController : ApiController
{
//GET api/AdditionalInfo
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
//GET api/AdditionalInfo/5
public string Get(int id)
{
return "value";
}
//PUT api/AdditionalInfo/5
public void Put(int id)
{
string test = "";
}
}
My Ajax Request from jQuery looks like this:
function GetAdditionalInfo(obj)
{
var request = jQuery.ajax({
url: "/api/AdditionalInfo/Get",
type: "GET",
data: { id: obj.id },
datatype: "json",
async: false,
beforeSend: function () {
},
complete: function () {
}
})
.done(function (a,b,c) {
alert("Additional info was retrieved successfully!");
})
.fail(function (a,b,c) {
alert("An error happened while trying to get the additional info!");
});
}
My WebAPIConfig file looks like this:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
And last but not least, this is my problem: this error message keeps appearing when I browse the returned data variable in .fail and this is what is written:
"{
"Message":"No HTTP resource was found that matches the request URI 'http://localhost:59096/api/AdditionalInfo/Get?id=1'.",
"MessageDetail":"No type was found that matches the controller named 'AdditionalInfo'."
}"
I would really appreciate it if someone could help me as soon as possible. Thanks in advance!
Best regards,
Mad

Looking at the error looks like Web API is unable to find the controller 'type' AdditionalInfo. Web API uses assemblies resolver to scan through the assemblies and finds out the controller types. In your case for some reason its unable to find your 'AdditionalInfo' controller probably because it has some problem loading the assembly having this controller.
Try the following and see if there are any errors logged in your EventLog. If you notice any errors then probably you should check if your controllers are present in those assemblies.
Make the following change in Web.config to view errors in EventLog
<system.diagnostics>
<trace autoflush="false" indentsize="4">
<listeners>
<add name="myListener"
type="System.Diagnostics.EventLogTraceListener"
initializeData="WebApiDiagnostics" />
</listeners>
</trace>
</system.diagnostics>
In your WebApiConfig.cs, you can do the following:
IAssembliesResolver assembliesResolver = config.Services.GetAssembliesResolver();
ICollection<Assembly> assemblies = assembliesResolver.GetAssemblies();
StringBuilder errorsBuilder = new StringBuilder();
foreach (Assembly assembly in assemblies)
{
Type[] exportedTypes = null;
if (assembly == null || assembly.IsDynamic)
{
// can't call GetExportedTypes on a dynamic assembly
continue;
}
try
{
exportedTypes = assembly.GetExportedTypes();
}
catch (ReflectionTypeLoadException ex)
{
exportedTypes = ex.Types;
}
catch (Exception ex)
{
errorsBuilder.AppendLine(ex.ToString());
}
}
if (errorsBuilder.Length > 0)
{
//Log errors into Event Log
Trace.TraceError(errorsBuilder.ToString());
}
BTW, some of the above code is actually from the DefaultHttpControllerTypesResolver which Web API uses to resolve the controller types.
http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Http/Dispatcher/DefaultHttpControllerTypeResolver.cs
Edited:
One more scenario where you could hit this problem is if your controller is nested inside another class. This was a bug which was fixed later though.

Ok, so I believe I found out what was going on. I am not entirely certain, but at least my problem got fixed.
Simply by changing what was inside of the "data" field in the Ajax call and I have created a class for an object in the application to hold the whole data. It seems that for some reason the method could not have the syntax "Get(int ID)".
Instead, I did something like "Get( object)" and in the Ajax Request something like "data: obj.ID" and voila, it worked.
Also, since the framework is picky about the names of the REST methods (Get, Post, Put and Delete), I changed the name of the method to something else (like Retrieve or something).
Hopefully this will help someone in the future as well.
Best regards,
Mad

Be sure that you have the same parameter names in your methods (int id) as well as in your WebApiConfig/RouteConfig. Try it by changing
public string Get(int id)
{
return "hello";
}
to
public string Get(int? id = null)
{
return "hello";
}

I had the same problem. with me it happens due to a crush in the visual studio (2012). I had the controller file open in visual studio but it wasn't a part of my solution - I couldn't find him in the controllers directory in the solution explorer.
I just added the file to the solution by right clicking on controllers directory => add => existing item.
that fixed the problem for me.
if that doesn't work maybe try to delete the controller and add a new one with the same code . . .

Related

vue testing vuetify input for disabled

I am very new to testing and I'm struggling my way through all this new stuff I am learning. Today I want to write a test for a vuetify <v-text-field> component like this:
<v-text-field
v-model="user.caption"
label="Name"
:disabled="!checkPermissionFor('users.write')"
required
/>
my test should handle the following case:
an active, logged in user has a array in vuex store which has his permissions as a array of strings. exactly like this
userRights: ['dashboard', 'imprint', 'dataPrivacy']
the checkPermissionFor() function is doing nothing else then checking the array above with a arr.includes('x')
after it came out the right is not included it gives me a negotiated return which handles the disabled state on that input field.
I want to test this exact scenario.
my test at the moment looks like this:
it('user has no rights to edit other user overview data', () => {
const store = new Vuex.Store({
state: {
ActiveUser: {
userData: {
isLoggedIn: true,
isAdmin: false,
userRights: ['dashboard', 'imprint', 'dataPrivacy']
}
}
}
})
const wrapper = shallowMount(Overview, {
store,
localVue
})
const addUserPermission = wrapper.vm.checkPermissionFor('users.write')
const inputName = wrapper.find(
'HOW TO SELECT A INPUT LIKE THIS? DO I HAVE TO ADD A CLASS FOR IT?'
)
expect(addUserPermission).toBe(false)
expect(inputName.props('disabled')).toBe(false)
})
big questions now:
how can I select a input from vuetify which has no class like in my case
how can I test for "is the input disabled?"
wrapper.find method accepts a query string. You can pass a query string like this :
input[label='Name'] or if you know the exact index you can use this CSS query too : input:nth-of-type(2).
Then find method will return you another wrapper. Wrapper has a property named element which returns the underlying native element.
So you can check if input disabled like this :
const buttonWrapper = wrapper.find("input[label='Name']");
const isDisabled = buttonWrapper.element.disabled === true;
expect(isDisabled ).toBe(true)
For question 1 it's a good idea to put extra datasets into your component template that are used just for testing so you can extract that element - the most common convention is data-testid="test-id".
The reason you should do this instead of relying on the classes and ids and positional selectors or anything like that is because those selectors are likely to change in a way that shouldn't break your test - if in the future you change css frameworks or change an id for some reason, your tests will break even though your component is still working.
If you're (understandably) worried about polluting your markup with all these data-testid attributes, you can use a webpack plugin like https://github.com/emensch/vue-remove-attributes to strip them out of your dev builds. Here's how I use that with laravel mix:
const createAttributeRemover = require('vue-remove-attributes');
if (mix.inProduction()) {
mix.options({
vue: {
compilerOptions: {
modules: [
createAttributeRemover('data-testid')
]
}
}
})
}
as for your second question I don't know I was googling the same thing and I landed here!

Ionic2: invalid page component: ProjectInfoPage

export class ProjectDetail {
page: string;
}
the page info contained in json, like this:
{
"data":[
{
page: "PageInfoPage"
},
{
page: "PageInfoPage1"
}
]
}
I parse info from this json,then saved in Array.
when execute this.nav.push(pd.page),throw exception as title described.I don't know how to convert 'string' to 'component'.
============================================================
I use the method like Angular 2 - Resolve Component Factory with a string described. This is my code:
itemClick(pd: ProjectDetail) {
var factories = Array.from(this.resolver['_factories'].keys());
var factoryClass = <Type<any>>factories.find((x: any) => x.name === pd.page);
const factory = this.resolver.resolveComponentFactory(factoryClass);
const compRef = this.vcRef.createComponent(factory);
if (this.componentRef) {
this.componentRef.destroy();
}
this.componentRef = compRef;
this.nav.push(compRef, {
item: pd,
pid: this.project.pid
});
}
it still does not work.Thank you for your answer.
At last,I solved it with a stupid method.As I create a map like this:
componentRegistry = {
'ProjectInfoPage': ProjectInfoPage
};
And then push like this:
this.nav.push(this.componentRegistry[pd.page], {
item: pd,
pid: this.project.pid
});
Normally, you have to import the actual component class for the page that you want to navigate to and then push that class onto the stack. By default, there is no way built into ionic2 to navigate via string references. I had the same problem today where I wanted to be able to navigate using strings rather than pushing the component class on the stack.
Check out the following link from the ionic forums on how to accomplish this. Look at the last two responses to the thread, which include how to solve this problem from beta stages and then an updated answer for how to do so with ionic 2.2.0. Although I'm pretty sure the same solution will work for all versions of ionic 2 since final release.
https://forum.ionicframework.com/t/ionic2-navigation-circular-depencies/41123/5

Tracking a Page Event from ASHX Handler

Im currently trying to track a PageEvent within a ASHX Handler. My code basically looks like this:
public class GetProductPdf : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (!Tracker.IsActive)
{
Tracker.Initialize();
Tracker.StartTracking();
}
//Track PageEvent here...
}
public bool IsReusable
{
get
{
return false;
}
}
}
The Tracker is always inactive and Tracker.Current == null. On method call "Tracker.StartTracking();" the following Exception is thrown:
[InvalidOperationException: Tracker.Current is not initialized]
Sitecore.Analytics.Pipelines.StartAnalytics.StartTracking.Process(PipelineArgs args) +317
(Object , Object[] ) +83
Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args) +445
Project.Web.Handler.PdfCreation.GetProductPdf.ProcessRequest(HttpContext context) in d:\Project\Website\Handler\PdfCreation\GetProductPdf.ashx.cs:69
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +913
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +165
I tried all possible solutions suggested here.
When doing the same in a mvc controller the Tracker is active and Tracker.Current != null.
Does anyone has an idea, what could cause this or are there any other suggestions for a solution?
Thanks in advance.
I am not certain that your Ashx Handler can be executed within the necessary Sitecore Context so that Tacker.Current will not be valid nor can be started via Tracker.StartTracking(). Someone might be able to confirm but I have another solution you can try which works for me.
As nice as it would be for the Ashx Handler to register the Event for you, instead you can fire a JavaScript function on the link to the file. So that when the link is clicked the JavaScript makes a web request to a MVC Controller and the controller registers the event for you.
I have implemented this myself using WebApi Controllers. Data Attributes were on the a tag, JavaScript posted those attributes to the controller, the controller used those attributes to determine which Event to register and the description to use on the Event.
<asp:HyperLink runat="server" data-goalid="{08030449-A811-428B-95F0-59FCD42B8DEB}" data-goaldescription="Product 0112 brochure">
[System.Web.Mvc.HttpPost]
public JsonResult RegisterGoal(string goalId, string goalDescription)
{
Item eventItem = Sitecore.Context.Database.GetItem(goalId);
var goal = new PageEventItem(eventItem);
var eventData = Tracker.Current.PreviousPage.Register(goal);
eventData.Data = goal["Description"] + " " + goalDescription;
Tracker.Current.Interaction.AcceptModifications();
return Json(new PageEventRequestResult()
{
Success = true,
Message = "Successfully registered goal",
});
}
It works really well. The only downside is having to add it to the various links that lead to the files you want to track.
I wrote a blog about tracking various interactions on a site and registering Sitecore Events / Goals you might want to look at, scroll down to the 'Storing custom data in xDB' section.

Issue testing Laravel Controller with Mockery | trying to get property of non-object

I'm very new to testing controllers and I'm running into a problem with a method(). I believe I'm either missing something in my test or my Controller / Repository is designed incorrectly.
The application I'm writing is basically one of those secure "one time" tools. Where you create a note, the system provides you with a URL, once that url is retrieved the note is deleted. I actually have the application written but I am going back to write tests for practice (I know that's backwards).
My Controller:
use OneTimeNote\Repositories\NoteRepositoryInterface as Note;
class NoteController extends \Controller {
protected $note;
public function __construct(Note $note)
{
$this->note = $note;
}
public function getNote($url_id, $key)
{
$note = $this->note->find($url_id, $key);
if (!$note) {
return \Response::json(array('message' => 'Note not found'), 404);
}
$this->note->delete($note->id);
return \Response::json($note);
}
...
I've injected my Note interface in to my controller and all is well.
My Test
use \Mockery as M;
class OneTimeNoteTest extends TestCase {
public function setUp()
{
parent::setUp();
$this->mock = $this->mock('OneTimeNote\Repositories\EloquentNoteRepository');
}
public function mock($class)
{
$mock = M::mock($class);
$this->app->instance($class, $mock);
return $mock;
}
public function testShouldReturnNoteObj()
{
// Should Return Note
$this->mock->shouldReceive('find')->once()->andReturn('test');
$note = $this->call('GET', '/note/1234567890abcdefg/1234567890abcdefg');
$this->assertEquals('test', $note->getContent());
}
}
...
The error I'm getting
1) OneTimeNoteTest::testShouldReturnNoteObj
ErrorException: Trying to get property of non-object
/Users/andrew/laravel/app/OneTimeNote/Controllers/NoteController.php:24
Line 24 is in reference to this line found in my controller:
$this->note->delete($note->id);
Basically my abstracted repository method delete() obviously can't find $note->id because it really doesn't exist in the testing environment. Should I create a Note within the test and try to actually deleting it? Or would that be something that should be a model test? As you can see I need help, thanks!
----- Update -----
I tried to stub the repository to return a Note object as Dave Marshall mentioned in his answer, however I'm now receiving another error.
1) OneTimeNoteTest::testShouldReturnNoteObj
BadMethodCallException: Method Mockery_0_OneTimeNote_Repositories_EloquentNoteRepository::delete() does not exist on this mock object
I do have a delete() method in my repository and I know it's working when I test my route in the browser.
public function delete($id)
{
Note::find($id)->delete();
}
You are stubbing the note repository to return a string, PHP is then trying to retrieve the id attribute of a string, hence the error.
You should stub the repository to return a Note object, something like:
$this->mock->shouldReceive('find')->once()->andReturn(new Note());
Building upon Dave's answer, I was able to figure out what my problem is. I wasn't mocking the delete() method. I didn't understand the need to mock each individual method in my controller that would be called.
I just added this line:
$mock->shouldReceive('delete')->once()->andReturnNull();
Since my delete method is just deleting the note after it is found, I went ahead and mocked it but set it to return null.

Is it possible to create an email-attachment on a Silverlight email?

I need to be able to send an email from a silverlight client-side application.
I've got this working by implementing a webservice which is consumed by the application.
The problem is that now I need to be able to add an attachment to the emails that are being sent.
I have read various posts, tried a dozen times to figure it out by myself, but to no prevail.
So now I find myself wondering if this is even possible?
The main issue is that the collection of attachments needs to be serializable. So, going by this, ObservableCollection - of type(FileInfo) is not working, ObservableCollection - of type (object) is not working... I've tried using List - of type(Stream), which serializes, but then i do not know how to create the file on the webservice side, as the stream-object does not have a name (which is the first thing I tried to assign to the Attachment object which will then be added to the message.attachments)... I'm kind of stuck in a rut here.
Can anybody maybe shed some light on this please?
I figured out how to do this, and it wasn't really as difficult as it appeared.
Create the following in your webservice-namespace:
`
[Serializable]
public class MyAttachment
{
[DataMember]
public string Name { get; set; }
[DataMember]
public byte[] Bytes { get; set; }
}`
Then add the following to your web-method parameters:
MyAttachment[] attachment
Add the following in the execution blocks of your web-method:`
foreach (var item in attachment)
{
Stream attachmentStream = new MemoryStream(item.Bytes);
Attachment at = new Attachment(attachmentStream, item.Name);
msg.Attachments.Add(at);
}`
Create the following property (or something similar) at your client-side:
`
private ObservableCollection<ServiceProxy.MyAttachment> _attachmentCollection;
public ObservableCollection<ServiceProxy.MyAttachment> AttachmentCollection
{
get { return _attachmentCollection; }
set { _attachmentCollection = value; NotifyOfPropertyChange(() => AttachmentCollection); }
}`
New up the public property (AttachmentCollection) in the constructor.
Add the following where your OpenFileDialog is supposed to return files:`
if (openFileDialog.File != null)
{
foreach (FileInfo fi in openFileDialog.Files)
{
var tempItem = new ServiceProxy.MyAttachment();
tempItem.Name = fi.Name;
var source = fi.OpenRead();
byte[] byteArray = new byte[source.Length];
fi.OpenRead().Read(byteArray, 0, (int)source.Length);
tempItem.Bytes = byteArray;
source.Close();
AttachmentCollection.Add(tempItem);
}
}`
Then finally where you call your web-method to send the email, add the following (or something similar):
MailSvr.SendMailAsync(FromAddress, ToAddress, Subject, MessageBody, AttachmentCollection);
This works for me, the attachment is sent with the mail, with all of its data exactly like the original file.