MVC4 AngularJS Removing # From Urls In Areas Applications - javascript

Before Posting This Question I Searched And Tried Out Many Examples As Well.
For My Problem There Was A Similar POST But It is Not Working Too.
Here Is The Structure Of MY Whole APPLICATION:
Here Is The Structure Of ADMIN AREA :
Project Has Two Applications Now One For Client And Another For Admin :
Admin Is Managed Through Areas
I Have Used Angular 1.3.5 And It is Used Inside The Areas.
The Landing Page Is Index Page of Home Controller Path :- Areas/Admin/Views/Home/Index.cshtml
Layout is _Layout Path : Areas/Admin/Views/Shared/_Layout.cshtml
RouteConfig.cs File Of Inside App_Start Folder :
namespace StockManagment
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces : new []{"StockManagment.Controllers"}
);
}
}
}
AdminAreaRegistration.cs
namespace StockManagment.Areas.Admin
{
public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Admin";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new [] {"StockManagment.Areas.Admin.Controllers"}
);
}
}
}
HTML5MODE For Removing # Form URL
myApp.config(["$locationProvider", function ($locationProvider) {
$locationProvider.html5Mode(true);
}]);
Base Tag In _Layout Page:
<base href="/">
Web.config Code Of Admin Areas
<rewrite>
<rules>
<rule name="Main Rule" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
When I Try To Access Admin Side Using This URL:
http://localhost:8917/Admin/Home/Index
It Loads The Website At : localhost:8917/
And If I Refresh The Page It Loads The Original Content i.e The Client Side Home Page.
Where Am I Going Wrong In This ?
Thanks In Advance...
Edit 1 :
i removed the rewrite code in web.config i used it because i saw it in another post
before using
myApp.config(["$locationProvider", function ($locationProvider) {
$locationProvider.html5Mode(true);
}]);
and
<base href="#Request.Url.AbsolutePath" />
to access admin side home page the url was :- http://localhost:8917/Admin/Home/Index#/
after adding the above code it is :- http://localhost:8917/Admin/Home/
accessing categories page
categories before code :- http://localhost:8917/Admin/Home/Index#/Categories
categories after code :- http://localhost:8917/Admin/Home/Categories
when i refresh it gives error
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /Admin/Home/Categories

I'm not sure why you're using the rewrite rule, I can imagine this would interfere with the routing you are trying to do with MVC. I would suggest removing the url rewrite rule from the web.config.
If you want a collection of routes to map to the Index action in the admin area (so that various urls go to your angular SPA), use a wildcard MVC route.
e.g.
// Route override to work with Angularjs and HTML5 routing
context.MapRoute(
name: "Application1Override",
url: "Application1/{*.}",
defaults: new { controller = "Application1", action = "Index" }
);

In your initial problem you had
<base href="/" />
which tells angular that the basic routing is "/", so it will change the href to the base ("/") when you reload the page, MVC will take you to "/" which is your root action.
When you are changing to -
<base href="#Request.Url.AbsolutePath" />
angular will know the base of this page is your current {action}/{controller}
Now you have another problem with the routing:
namespace StockManagment.Areas.Admin
{
public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Admin";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}", // your current url= /Admin/Home/Categories -- which means id = Categories
new { action = "Index", id = UrlParameter.Optional },
new [] {"StockManagment.Areas.Admin.Controllers"}
);
}
}}
If you don't need ID you can use this code:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{*angular}",
new { action = "Index",
new [] {"StockManagment.Areas.Admin.Controllers"}
);
}

Related

Magento 2 Knockout XML->PHTML->JS->HTML

I want to display static block in html login popup during checkout, but there is a problem.
This is the html template which is called from js, this js is called from phtml, and this phtml template called from xml
layout.
( xml -> phtml -> js -> html)
So the question is how to send custom content block from the phtml or xml throught js to html template
vendor/magento/module-catalog/view/frontend/layout/default.xml
This file is calling pthml template with
<block class="Magento\Customer\Block\Account\AuthenticationPopup" name="authentication-popup" as="authentication-popup" template="Magento_Customer::account/authentication-popup.phtml">
vendor/magento/module-customer/view/frontend/templates/account/authentication-popup.phtml
This file is calling js layout with code:
<script type="text/x-magento-init">
{
"#authenticationPopup": {
"Magento_Ui/js/core/app": <?= /* #noEscape */ $block->getJsLayout() ?>
}
}
</script>
vendor/magento/module-customer/view/frontend/web/js/view/authentication-popup.js
this file is called the last html template where should be a static block from admin panel, with code:
define([
'jquery',
'ko',
// ......... //
], function ($, ko, /* ... ... ... .... ... */) {
'use strict';
return Component.extend({
registerUrl: window.authenticationPopup.customerRegisterUrl,
forgotPasswordUrl: window.authenticationPopup.customerForgotPasswordUrl,
autocomplete: window.authenticationPopup.autocomplete,
modalWindow: null,
isLoading: ko.observable(false),
defaults: {
template: 'Magento_Customer/authentication-popup'
},
});
});
this is how i get this block in php
<?php echo $this->getLayout()->createBlock('Magento\Cms\Block\Block')->setBlockId('reset_password_notice')->toHtml(); ?>
I tried to paste it to phtml, it doesn't work !!!
The problem is solved by myself.
So for the first step i started looking for data provider which helps to send data from pthml throught js to html in vendor/module-customer/
There i found file vendor/module-customer/Model/Checkout/ConfigProvider.php. That was exectly what i need.
Following this link i create:
1) app/code/Theme/Customer/etc/frontend/di.xml with code:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Customer\Controller\Account\CreatePost"
type="Theme_Name\Customer\Controller\Account\CreatePost" />
<type name="Magento\Checkout\Model\CompositeConfigProvider">
<arguments>
<argument name="configProviders" xsi:type="array">
<item name="cms_block_config_provider" xsi:type="object">Theme_Name\Customer\Model\Checkout\ConfigProvider</item>
</argument>
</arguments>
</type>
</config>
2) The next step was to create a class which is called in item tag: Theme_Name/Customer/Model/Checkout/ConfigProvider.php
with code that extends
vendor/module-customer/Model/Checkout/ConfigProvider.php
Note! They both implement the same ConfigProviderInterface. So in new ConifgProvider.php we use the same interface to extend data-provider correctly
<?php
namespace Theme_Name\Customer\Model\Checkout;
use Magento\Checkout\Model\ConfigProviderInterface;
use Magento\Framework\View\LayoutInterface;
class ConfigProvider implements ConfigProviderInterface
{
/** #var LayoutInterface */
protected $_layout;
public function __construct(LayoutInterface $layout)
{
$this->_layout = $layout;
}
public function getConfig()
{
$cmsBlockId = 'block_ID'; // id of cms block to use
return [
'cms_block_message' => $this->_layout->createBlock('Magento\Cms\Block\Block')->setBlockId($cmsBlockId)->toHtml()
];
}
}
Good. Provider is configured.
3)The last one was need to override frontend html KO template:
app/design/frontend/theme_name/Magento_Customer/web/template/authentication-popup.html
Write the next:
<div data-bind="html: window.checkoutConfig.cms_block_message"></div>
You need to put this code into your phtml file.
<?php echo $this->getLayout()->createBlock('Magento\Cms\Block\Block')->setBlockId('reset_password_notice')->toHtml(); ?>
And now it show what you write into this block.

JavaScript calling controller for session clear not working

I am calling a controller that redirects url. Usercontroller.cs has a ClearSessionAnCoodkies method.
I have added the route for this httpget method ClearSessionAndCookies().
Used JQuery for calling the controller method to clear the session variable and redirect tot he home page.
For some reason the call is failing and not redirecting to the home page.
Application says 404 page not found. Not sure why the call is failing :(
The following is the controller, router, and asp.net call
----------
**UserController.cs**
[HttpGet]
public IHttpActionResult ClearSessionAndCookies()
{
HttpContext.Current.Session.Clear();
HttpContext.Current.Session.Abandon();
HttpContext.Current.Session.RemoveAll();
var host = Request.RequestUri.GetLeftPart(UriPartial.Authority);
return Redirect(host + "/cp");
}
**Routing**
RouteTable.Routes.MapHttpRoute(
name: "User",
routeTemplate: "api/User",
defaults: new { action = "ClearSessionAndCookies", controller = "User" }
);
**JavaScirpt**
function RedirectToWelcomePage() {
message = "Session expired. You will be redirected to home page.";
$('#sessionTimeoutTitle').text(message);
$('#sessionTimeoutModal').modal('show');
var url = 'api/User/ClearSessionAndCookies';
$.post(url, function (res) {
if (res.Success) {
sessionStorage.clear();
window.location.href = res.RedirectUrl;
}
}); }
The problem is that you are declaring the action as Get and then are calling this with a post.
[HttpGet]
public IHttpActionResult ClearSessionAndCookies()
$.post(url, function (res) {
Remove the [HttpGet] attribute and this will work.
Your route map says that if a user hits api/User it will call ClearSessionAndCookies. If you want the action in the url you may need to update your routing.
I highly recommend Route Attributes as they are cleaner to ready.
https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/routing

Pass an array via AJAX call and struts2 to a java class

Javascript-AJAX call
function assignTask(){
var formdata = "xyz";
var taskList = [];
$.each($("input[name='taskname']:checked"), function(){
taskList.push($(this).val());
});
$.ajax({
type: "post",
data: {taskList:taskList},
url: "AssignTask" ,
traditional: true,
success: function (data)
{
........}
});
}
Now var taskList is storing array successfully. Since i have checked that already.
The problem happens inside the AJAX function while sending the array taskList.
struts.xml
<struts>
<constant name="struts.custom.i18n.resources" value="ApplicationResources"/>
<package name="default" extends="struts-default" >
<action name="AssignTask" class="dto.Task" method="assignTasks">
<result name="success">jsp/TaskList.jsp</result>
</action>
</package>
</struts>
dto.Task java class with method assignTasks()
public class Task extends ActionSupport {
private ArrayList<Task> taskList;
public ArrayList<Task> getTaskList() {
return taskList;}
public void setTaskList(ArrayList<Task> taskList) {
this.taskList = taskList;
}
public String assignTasks() {
System.out.println("Inside assign tasks..."+ taskList.size());
String result = "success";
return result;
}
}
When I am running the application in Netbeans, glassfish console is showing me this error:
Warning: Could not find action or result
No result defined for action dto.Task and result input
at at com.opensymphony.xwork2.DefaultActionInvocation......
......
Google Chrome console is showing me this error:
jquery.min.js:4 POST http://localhost:8080/EmployeeManagement/AssignTask 404
(No result defined for action dto.Task and result input)
So my program's control is not going inside the function assignTasks() and of course there is a problem in passing array from AJAX function to the dto.Task java class via struts2 framework.
Please help me solve it.

​
Could you try adding namespace attribute as below?
<package name="default" extends="struts-default" namespace="/">
...
</package>

Custom cordova plugin creation for ionic2 project

Many of us would have gone through similar issues, but even after going through following most relevant links reference link1 and reference link2 , I am not able to resolve.
Issue:
Create a custom plugin (Cordova) in-order to use this in ionic2
project.
Expectation: This plugin will be able to interact with native features of IOS and Android. To be precise I am trying to access features of a native SDK (Aruba Internal Positioning SDK) using cordova into Ionic project.
Step 1 Initially created plugin as per reference link 1
Step 2 Created Ionic 2 project( created with this basic steps )
Step 3 JavaScript file in plugin was not able to refer and access in Ionic2 .
After googling , I found this discussion , where it is told to create interface in plugin itself because of the following reason.
import {myPluginName} from '../../../plugins/xxx/*.js'
Will not work because the plugin is not part of the ionic native bundle.
If you have a custom plugin, you can do a few things.
1) Make a PR to add it to ionic-native proper
2) Use the raw plugin API.
You can use the raw plugin API without having it be part of Ionic Native.
The plugin is on the window object, so you would target the api normally
window.plugin.myPlugin.myMethod()
According to the GITHUB Example project this way the interface should be implemented
interface CordovaPlugins {
ZPLPrinter: ZPLPrinter;
}
interface ZPLPrinter {
print(
ipaddress: string,
bclabels: any,
printSuccess: (ip: string, labels: string[]) => void,
printError: (message: string) => void): void;
}
Now I created a similar interface in my plugin which is the following in plugin's www folder
interface CordovaPlugins {
Communicator: Communicator;
}
interface Communicator {
getInfo(successCallback: any, errorCallback: any);
}
This interface would ideally target this method in JS file
Device.prototype.getInfo = function(successCallback, errorCallback) {
console.log("device.js: getInfo function called");
argscheck.checkArgs('fF', 'Device.getInfo', arguments);
exec(successCallback, errorCallback, "Device", "getDeviceInfo", []);
};
Now I am stuck , as my Ionic project is not having typings folder itself.
In the sample Github Project, cordova packages are referred using typings folder . TypeScript File in project is referring Cordova using index.t.js
Import used to refer should go like
declare var cordova: Cordova;
Doubts:
Am I in the wright direction of the process
Is this the way to create Cordova plugin and use in ionic
Why I am not able to get typings folder in Ionic2
EDIT 1:
After just adding the plugin without even referring in Ionic project, I tried to run in Android device. But it gave me the following error.
Main error is this
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ionicframework.cutepuppypics234138/com.ionicframework.cutepuppypics234138.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void org.apache.cordova.CordovaPlugin.privateInitialize(java.lang.String, org.apache.cordova.CordovaInterface, org.apache.cordova.CordovaWebView, org.apache.cordova.CordovaPreferences)' on a null object reference
Why would this error be causing? Detailed logs have given below
12-08 16:10:49.079 20555-20555/? E/ApkAssets: Error while loading asset assets/natives_blob_64.bin: java.io.FileNotFoundException: assets/natives_blob_64.bin
12-08 16:10:49.079 20555-20555/? E/ApkAssets: Error while loading asset assets/snapshot_blob_64.bin: java.io.FileNotFoundException: assets/snapshot_blob_64.bin
12-08 16:10:49.682 20555-20555/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.ionicframework.cutepuppypics234138, PID: 20555
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ionicframework.cutepuppypics234138/com.ionicframework.cutepuppypics234138.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void org.apache.cordova.CordovaPlugin.privateInitialize(java.lang.String, org.apache.cordova.CordovaInterface, org.apache.cordova.CordovaWebView, org.apache.cordova.CordovaPreferences)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2339)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2413)
at android.app.ActivityThread.access$800(ActivityThread.java:155)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1317)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5343)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void org.apache.cordova.CordovaPlugin.privateInitialize(java.lang.String, org.apache.cordova.CordovaInterface, org.apache.cordova.CordovaWebView, org.apache.cordova.CordovaPreferences)' on a null object reference
at org.apache.cordova.PluginManager.getPlugin(PluginManager.java:171)
at org.apache.cordova.PluginManager.startupPlugins(PluginManager.java:97)
at org.apache.cordova.PluginManager.init(PluginManager.java:86)
at org.apache.cordova.CordovaWebViewImpl.init(CordovaWebViewImpl.java:115)
at org.apache.cordova.CordovaActivity.init(CordovaActivity.java:149)
at org.apache.cordova.CordovaActivity.loadUrl(CordovaActivity.java:224)
at com.ionicframework.cutepuppypics234138.MainActivity.onCreate(MainActivity.java:39)
at android.app.Activity.performCreate(Activity.java:6010)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1129)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2292)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2413) 
at android.app.ActivityThread.access$800(ActivityThread.java:155) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1317) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:135) 
at android.app.ActivityThread.main(ActivityThread.java:5343) 
at java.lang.reflect.Method.invoke(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:372) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700) 
12-08 16:10:49.879 20656-20656/? E/SubDex: SubDex Config : .dex 2
12-08 16:10:50.285 20656-20656/? E/project: extsdcard==/storage/emulated/0/Android/data/com.cleanmaster.mguard/files
12-08 16:10:50.303 20656-20656/? E/project: extsdcard==/storage/emulated/0/Android/data/com.cleanmaster.mguard/files
After many trial and errors I found the solution.
I am putting down below details for future reference to any one who is trying a similar stuff!
Issues with code was as follows (my plugin name is Inject)
Inject\www\Inject.js was not having essential function for installing the plugin
Any method name mentioned in Inject.js should be same till Inject\src\Inject.java as there are options in execute method to refer different method name based on tag's received
Steps:
Use plugman to create skeleton of plugin Reference Link
Instead of using names like cordova-plugin-am-i-late , use cordova.plugin.Inject . I faced compile/run time issues using - symbol
Add targeted platform plugman platform add --platform_name android
Verify plugin.xml comparing the same reference
Include permissions in plugin.xml if required
Now verify Inject.js its missing essential method calls. Currently its having only the following code.
var exec = require('cordova/exec');
exports.coolMethod = function(arg0, success, error) {
exec(success, error, "Inject", "coolMethod", [arg0]);
};
But we need to include below also to make it install and work
function Inject(){
}
Inject.install = function () {
if (!window.plugins) {
window.plugins = {};
}
window.plugins.Inject = new Inject();
return window.plugins.Inject;
};
cordova.addConstructor(Inject.install);
For example I am targeting to show a Toast message for which below is my complete Inject.js file
function Inject(){
}
Inject.prototype.coolMethod = function (options, successCallback, errorCallback) {
cordova.exec(successCallback, errorCallback, "Inject", "coolMethod", []);
};
Inject.install = function () {
if (!window.plugins) {
window.plugins = {};
}
window.plugins.Inject = new Inject();
return window.plugins.Inject;
};
cordova.addConstructor(Inject.install);
Now lets implement our Inject.java
public class Inject extends CordovaPlugin {
private static final int GRAVITY_CENTER = Gravity.CENTER_VERTICAL|Gravity.CENTER_HORIZONTAL;
private static final String TAG = "InjectCordovaPlugin";
String messageReceived;
#Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
Log.v(TAG, "execute , action =" + action);
if (action.equals("coolMethod")) {
String message = args.getString(0);
Log.v(TAG, "coolMethod called with message =" + message);
this.coolMethod(message, callbackContext);
return true;
}
return false;
}
private void coolMethod(String message, CallbackContext callbackContext) {
Log.v(TAG, "Inject's coolMethod called ,message="+message);
messageReceived = message;
if (message != null && message.length() > 0) {
cordova.getActivity().runOnUiThread(new Runnable() {
public void run() {
final android.widget.Toast toast = android.widget.Toast.makeText(
cordova.getActivity().getWindow().getContext(),
messageReceived,
android.widget.Toast.LENGTH_LONG
);
toast.setGravity(GRAVITY_CENTER, 0, 0);
toast.show();
}
});
callbackContext.success(message);
} else {
callbackContext.error("Expected one non-empty string argument.");
}
}
}
Just to make this clear I'm putting out my final plugin.xml
<?xml version='1.0' encoding='utf-8'?>
<plugin id="cordova.plugin.Inject"
version="1"
xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android">
<name>Inject</name>
<js-module name="Inject" src="www/Inject.js">
<clobbers target="window.plugins.Inject"/>
</js-module>
<platform name="android">
<config-file parent="/*" target="res/xml/config.xml">
<feature name="Inject">
<param name="android-package"
value="cordova.plugin.Inject.Inject" />
</feature>
</config-file>
<config-file parent="/*" target="AndroidManifest.xml">
</config-file>
<source-file src="src/android/Inject.java"
target-dir="src/cordova.plugin.Inject/Inject" />
</platform>
</plugin>
Now create a sample Ionic2 project and add Android/IOS platform
Add the created plugin using cordova plugin add command
Navigate to ionic project in Nodejs command prompt and give this command (refer Plugin folder base after add ) cordova plugin add D:\PluginTrial\Inject
The added plugin should be populated under Ionic2Project\plugins folder
Call this function using window object. Below is my home.ts
import { Component } from '#angular/core';
import { NavController, Platform } from 'ionic-angular';
declare var window: any;
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(public navCtrl: NavController, private platform: Platform) {
}
showToast(message, position) {
this.platform.ready().then(() => {
window.plugins.Inject.coolMethod(message, "short", position);
});
}
}
Now refer this showToast method in home.html file
<button ion-button (click)="showToast('Yo Man! Its working ', 'center')">Default</button>
That's it. You should be able to test the plugin successfully! Happy Coding
Reference:
Reference One , Reference Two , Reference Three
Your plugin needs to look like this:
In: /[custom plugin name]/js/custom_plugin.js
var CustomPlugin = function(){};
CustomPlugin.someFunction = function(){
console.log("someFunction starts");
return new Promise(function(resolve,reject){
cordova.exec(
resolve,
reject,
[PLUGIN_NAME],
[ACTION_ON_NATIVE_SIDE],
[]
);
});
console.log("someFunction stops");
}
.... more functions
module.exports = CustomPlugin;
In: /[custom plugin name]/src/[android]||[ios] , the classes with native code.
And in: /[custom plugin name]/plugin.xml (this is an example, settings have to be adjusted to your case):
<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
id="[CustomPlugin]"
version="1.0.0">
<name>CustomPlugin</name>
<description>...</description>
<license>...</license>
<author>...</author>
<engines>
<engine name="cordova" version=">=6.0.0" />
</engines>
<js-module src="www/js/custom_plugin.js" name="CustomPlugin">
<clobbers target="CustomPlugin" />
</js-module>
<platform name="ios">
<config-file target="config.xml" parent="/*">
<preference name="orientation" value="portrait"/>
<feature name="CustomPlugin">
<param name="ios-package" value="CustomPlugin" />
<param name="onload" value="true"/>
</feature>
</config-file>
<header-file src="src/ios/CustomPlugin.h" />
<source-file src="src/ios/CustomPlugin.m" />
<!--framework src="QuartzCore.framework" />
<framework src="AssetsLibrary.framework" />
<framework src="CoreGraphics.framework" />
<framework src="MobileCoreServices.framework" /-->
</platform>
<platform name="android">
<config-file target="res/xml/config.xml" parent="widget">
<preference name="orientation" value="portrait"/>
<feature name="CustomPlugin" >
<param name="android-package" value="[package name].CustomPlugin"/>
<param name="onload" value="true"/>
</feature>
</config-file>
<config-file target="AndroidManifest.xml" parent="/*">
<supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
<uses-permission android:name="..." />
<uses-feature android:name="..." />
</config-file>
<source-file src="src/android/CustomPlugin.java" target-dir="[package folder directory organization like: com.android.something]" />
<source-file ... />
<source-file src="src/android/custom_plugin.xml" target-dir="res/layout" />
</platform>
</plugin>
then you add you plugin with the CLI: ionic plugin add [folder of your plugin]
In your Ionic project, in the classes (angular2 directives) where you want to use your plugin, write before the #Component section: declare var CustomPlugin: any;. Then in that class, you can use your plugin by refering to CustomPlugin that is exported with module.exports = CustomPlugin;
from the file: /[custom plugin name]/js/custom_plugin.js.
TO ANSWER EDIT 1 OF THE QUESTION, HERE SOME DETAILS OF THE ANDROID PART:
In the android plugin project (once platform android has been added and built at least once, with ionic CLI), in android studio (2.2.2), when looking at the build project under "[my project]\platforms\android":
In the hierarchy, the MainActivity file is autogenerated under:
"android\java\com\ionicframework.[my project name + a large number]\MainActivity":
package com.ionicframework.[my project name + a large number];
import android.os.Bundle;
import org.apache.cordova.*;
public class MainActivity extends CordovaActivity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// enable Cordova apps to be started in the background
Bundle extras = getIntent().getExtras();
if (extras != null && extras.getBoolean("cdvStartInBackground", false)) {
moveTaskToBack(true);
}
// Set by <content src="index.html" /> in config.xml
loadUrl(launchUrl);
}
}
For my custom plugin (not going into details here) under "android\java[package of the custom plugin]:
package [package of the custom plugin];
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
// + other imports needed
public class CustomPlugin extends CordovaPlugin {
private static CallbackContext customDeferredCallback;
public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException {
//all the thing corresponding to your case need to end if with either:
// if OK: callbackContext.success(); return true; ;
// if not OK: callbackContext.error(error.getMessage()); return false;
// if JAVA returns a result to JS do: actionBindListener(callbackContext);
}
private boolean actionBindListener(final CallbackContext callbackContext){
cordova.getThreadPool().execute(new Runnable() {
public void run(){
try{
customDeferredCallback= callbackContext;
}catch(Exception e){e.printStackTrace();}
}
});
return true;
}
//in your program when you get the result you want to send back to javascript call this function
public static void sendResultToJS(res){
JSONObject eventData = new JSONObject();
try {
eventData.put("CUSTOM_KEY", res);
} catch (JSONException e) {
e.printStackTrace();
}
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, eventData);
pluginResult.setKeepCallback(true);
try{
customDeferredCallback.sendPluginResult(pluginResult);
} catch(NullPointerException e){
e.printStackTrace();
}
}
}
And finally android\manifests\manifests.xml looks like that:
<?xml version='1.0' encoding='utf-8'?>
<manifest android:hardwareAccelerated="true" android:versionCode="1" android:versionName="0.0.1" package="com.ionicframework.[project name + large number]" xmlns:android="http://schemas.android.com/apk/res/android">
<supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
<uses-permission android:name="android.permission.INTERNET" />
<application android:hardwareAccelerated="true" android:icon="#mipmap/icon" android:label="#string/app_name" android:supportsRtl="true">
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="#string/activity_name" android:launchMode="singleTop" android:name="MainActivity" android:theme="#android:style/Theme.DeviceDefault.NoActionBar" android:windowSoftInputMode="adjustResize">
<intent-filter android:label="#string/launcher_name">
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:exported="true" android:name="com.adobe.phonegap.push.PushHandlerActivity" />
<receiver android:name="com.adobe.phonegap.push.BackgroundActionButtonHandler" />
<receiver android:exported="true" android:name="com.google.android.gms.gcm.GcmReceiver" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
<service android:exported="false" android:name="com.adobe.phonegap.push.GCMIntentService">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<service android:exported="false" android:name="com.adobe.phonegap.push.PushInstanceIDListenerService">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter>
</service>
<service android:exported="false" android:name="com.adobe.phonegap.push.RegistrationIntentService" />
</application>
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="24" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />
<permission android:name="${applicationId}.permission.C2D_MESSAGE" android:protectionLevel="signature" />
</manifest>
As far as typings is concerned, it is no longer used. All or most typescript declarations are moved to npm itself and you install them as npm install #types/package_name.
https://www.npmjs.com/~types
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/README.md
If you need typings folder you could try
npm install typings
you can also referance type declararions through
// <reference path="" />
in typescript

Sending image in base64 to Webservice - 'application/octet-stream' was not the expected type 'text/xml; charset=utf-8'

I'm trying to save an html5 canvas content, to localhost by using a webserver.
I'm getting the canvas value in base64 and I send it to my webservice.
But when I send the data to the webservice I get this error and the file is not saved:
415: "Cannot process the message because the content type
'application/octet-stream' was not the expected type 'text/xml;
charset=utf-8'."
What am I doing wrong?
Service.vb
Imports System.IO
Imports System.Drawing
Public Class Service
Implements IService
Public Sub New()
End Sub
Public Function savePictureBase64(bytes As Byte()) As Boolean Implements IService.savePictureBase64
Dim fullOutputPath As String = "c:\temp\file.png"
'get a temp image from bytes, instead of loading from disk
'data:image/gif;base64,
Dim imagem As Image
Using ms As New MemoryStream(bytes)
imagem = Image.FromStream(ms)
End Using
File.WriteAllBytes(fullOutputPath, (bytes))
Return True
End Function
End Class
IService.vb
<ServiceContract()>
Public Interface IService
<OperationContract()>
Function savePictureBase64(bytes As Byte()) As Boolean
' TODO: Add your service operations here
End Interface
Javascript
function save () {
var image = document.getElementById("sketchpad").toDataURL("image/png");
image = image.replace('data:image/png;base64,', '');
$.ajax({
type: 'POST',
url: 'http://localhost:52193/service.svc',
data: image,
contentType: 'application/octet-stream',
success: function (msg) {
alert('Image saved successfully !');
},
error: function(result) {
alert("Error");
}
});
}
</script>
web.config
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
</appSettings>
<system.web>
<compilation debug="true" strict="false" explicit="true" targetFramework="4.5"/>
<httpRuntime targetFramework="4.5"/>
<pages>
<namespaces>
<add namespace="System.Runtime.Serialization"/>
<add namespace="System.ServiceModel"/>
<add namespace="System.ServiceModel.Web"/>
</namespaces>
</pages>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding messageEncoding="Mtom">
</binding>
</basicHttpBinding>
</bindings>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https"/>
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
The error is the call that you made by Javascript code. You try to send a string, the webservice expected an XML message:
expected type 'text/xml; charset=utf-8'.
I don't know how complicated it is to compose a webservice XML message from Javascript, but I think that you can change your approach. Your service is hosted under IIS, can you build an HttpHandler?
public class UploadBase64 : IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
string image_string = string.Empty;
using (StreamReader sr = new StreamReader(context.Request.InputStream))
image_string = sr.ReadToEnd();
byte[] image_bin = Convert.FromBase64String(image_string);
File.WriteAllBytes(#"c:\temp_10\test01.png", image_bin);
}
}
...and add this to your web.config file:
<system.web>
<httpHandlers>
<add verb="POST" path="UploadBase64.aspx" type="WebApplication1.UploadBase64"/>
</httpHandlers>
</system.web>

Categories

Resources