Codeigniter:Soap Client call works well in PHP not in C# - c#

I created a SOAP server in codeigniter and here is my controller
class Sample extends CI_Controller {
function __construct()
{
parent::__construct();
$ns = base_url();
$this->load->library("Nusoap_library");
$this->load->library("Master");
$this->server = new soap_server(); // create soap server object
$this->server->configureWSDL("SOAP", $ns); // wsdl
$this->server->wsdl->schemaTargetNamespace = $ns; // server namespace
}
public function index()
{
$ns = base_url();
$input_array = array ('type' => "xsd:string"); // "addnumbers" method parameters
$return_array = array ("fruit" => "xsd:string");
$this->server->register('Master.fruits', $input_array, $return_array, "urn:SOAPServerWSDL", "urn:".$ns."/addnumbers", "rpc", "encoded", "Fruit Types");
$this->server->service(file_get_contents("php://input")); // read raw data from request body
}
public function client(){
$this->client = new nusoap_client(base_url()."index.php?wsdl", true);
$this->load->view("client");
}
}
the server is works very well, and i created a Mater class as library
Master.php [library]
class Master {
public function fruits($type)
{
switch($type)
{
case 'red':
return "Apple";
break;a
case 'yellow':
return "banana";
break;
}
}
}
As you can see the controller, i also created a client function to test whether the client working fine
here is my client View code
$error = $this->client->getError();
if ($error) {
echo "<h2>Constructor error</h2><pre>" . $error . "</pre>";
}
$result = $this->client->call("Master.fruits", array("type" => "red"));
if ($this->client->fault) {
echo "<h2>Fault</h2><pre>";
print_r($result);
echo "</pre>";
}
else {
$error = $this->client->getError();
if ($error) {
echo "<h2>Error</h2><pre>" . $error . "</pre>";
}
else {
echo "<h2>Fruits</h2><pre>";
echo $result;
echo "</pre>";
}
}
i am getting result perfectly in php while calling the SOAP server but if the same SOAP server is called via C# by creating service
i am getting errors something like it should not be like Master.fruits it should be like masterfruits and also i am getting errors in content Type

Related

CKEditor and C# Web API, upload image with simple upload plugin

In my project I use CKEditor WYSWYG package to make HTML content for my website.
There is possible to insert image and send it directly from the package to the server.
Since 2 days I try to figure out how is it possible to catch the sent image from the Angular front-end to the Web API, but still no success.
I use .Net6 and Angular 12 with CKEditor 5.
public async Task<ActionResult<string>> AddPostPhoto(IFormFile photo)
{
try
{
System.Console.WriteLine(Request.ContentType);
var folderDirectory = $"\\Photos\\PostPhotos";
var path = Path.Combine("Photos/PostPhotos", "fileName.jpg");
var memoryStream = new MemoryStream();
await Request.Body.CopyToAsync(memoryStream);
System.Console.WriteLine(Request.HttpContext.Request.ContentLength);
System.Console.WriteLine(Request.Form.Keys);
if (!Directory.Exists(folderDirectory))
{
Directory.CreateDirectory(folderDirectory);
}
await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write))
{
memoryStream.WriteTo(fs);
}
return Ok(new { Url = path });
}
catch(Exception exception)
{
return BadRequest(exception.Message);
}
}
Finally I could find a working solution.
my-upload-adapter.ts
//ckeditorExComponent class Ends here and MyUploadAdapter class begins here in the same ckeditorEx.ts
export class MyUploadAdapter {
xhr: any;
loader: any;
serverUrl: string;
baseApiUrl: string;
constructor(loader: any, serverUrl: string, baseApiUrl: string) {
// The file loader instance to use during the upload.
this.loader = loader;
this.serverUrl = serverUrl;
this.baseApiUrl = baseApiUrl;
}
// Starts the upload process.
upload() {
return this.loader.file
.then((file: any) => new Promise((resolve, reject) => {
this._initRequest();
this._initListeners(resolve, reject, file);
this._sendRequest(file);
}));
}
// Aborts the upload process.
abort() {
if (this.xhr) {
this.xhr.abort();
}
}
// Initializes the XMLHttpRequest object using the URL passed to the constructor.
_initRequest() {
const xhr = this.xhr = new XMLHttpRequest();
// Note that your request may look different. It is up to you and your editor
// integration to choose the right communication channel. This example uses
// a POST request with JSON as a data structure but your configuration
// could be different.
//Replace below url with your API url
xhr.open('POST', this.baseApiUrl + 'Tutorial/add-post-photo', true);
xhr.responseType = 'json';
}
// Initializes XMLHttpRequest listeners.
_initListeners(resolve: any, reject: any, file: any) {
const xhr = this.xhr;
const loader = this.loader;
const genericErrorText = `Couldn't upload file: ${file.name}.`;
xhr.addEventListener('error', () => reject(genericErrorText));
xhr.addEventListener('abort', () => reject());
xhr.addEventListener('load', () => {
const response = xhr.response;
// This example assumes the XHR server's "response" object will come with
// an "error" which has its own "message" that can be passed to reject()
// in the upload promise.
//
// Your integration may handle upload errors in a different way so make sure
// it is done properly. The reject() function must be called when the upload fails.
if (!response || response.error) {
return reject(response && response.error ? response.error.message : genericErrorText);
}
// If the upload is successful, resolve the upload promise with an object containing
// at least the "default" URL, pointing to the image on the server.
// This URL will be used to display the image in the content. Learn more in the
// UploadAdapter#upload documentation.
resolve({
default: this.serverUrl + response.url
});
});
// Upload progress when it is supported. The file loader has the #uploadTotal and #uploaded
// properties which are used e.g. to display the upload progress bar in the editor
// user interface.
if (xhr.upload) {
xhr.upload.addEventListener('progress', (evt: any) => {
if (evt.lengthComputable) {
loader.uploadTotal = evt.total;
loader.uploaded = evt.loaded;
}
});
}
}
// Prepares the data and sends the request.
_sendRequest(file: any) {
// Prepare the form data.
const data = new FormData();
data.append('upload', file);
// Important note: This is the right place to implement security mechanisms
// like authentication and CSRF protection. For instance, you can use
// XMLHttpRequest.setRequestHeader() to set the request headers containing
// the CSRF token generated earlier by your application.
// Send the request.
this.xhr.send(data);
}
}
In the Angular component
onReady($event: any) {
$event.plugins.get('FileRepository').createUploadAdapter = (loader: any) => {
return new MyUploadAdapter(loader, this.serverUrl, this.apiUrl);
};
}
The C# Web API controller
[HttpPost("add-post-photo")]
public async Task<ActionResult<string>> AddPostPhoto(IFormFile upload)
{
try
{
FileInfo fileInfo = new FileInfo(upload.FileName);
System.Console.WriteLine(upload.FileName);
var folderDirectory = $"\\Photos\\PostPhotos";
var path = Path.Combine("Photos\\PostPhotos", upload.FileName);
var memoryStream = new MemoryStream();
await upload.OpenReadStream().CopyToAsync(memoryStream);
if (!Directory.Exists(folderDirectory))
{
Directory.CreateDirectory(folderDirectory);
}
await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write))
{
memoryStream.WriteTo(fs);
}
return Ok(new { Url = path });
}
catch(Exception exception)
{
return BadRequest(exception.Message);
}
}
It is important to have the parameter upload, otherwise the find the back-end endpoint

Enable/ disable a button in Client when an event on server is finished

I am developing a .Net core project with Angular on Frontend and c# on backend. I am new to web development and i am looking for ideas or little help on achieving a task.
I am connecting my Angular frontend to an External server using .net web server. I am able to post data to External server successfully using Http services. After i receive response from external server the results are queued in my controller. Before i send response to client i want to enable a download button on Client, only if i receive response from the External server and the results are queued in my controller successfully. If there is no response from External server I do not want to enable download button.
Appcomponent.html
<button mat-button id="getdoc" (click) = "getdoc()" [disabled] = "disabled" >Download</button>
Appcomponent.ts
getdoc() {
this.download.downloadDoc()
.subscribe(res => {
this.datadownload = new Blob([res], { type: 'application/txt' });
// { this.disabled = false };
saveAs(this.datadownload);
console.log(this.datadownload);
}, error => {
console.log('error while downloading', error)
})
}
Appservice.ts
export class DownloadService {
constructor(private http: HttpClient) { }
downloadDoc(): Observable<any> {
return this.http.get('URL', {/* headers, */ reportProgress: true, responseType : "blob"});
}
}
Controller
namespace ang.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class DoController : Controller
{
private void OnProvideData(DataAndHeader dat)
{
CommHeader header = (CommHeader)dat.Header;
switch (header.Type)
{
case CommHelpers.CommType.ServerToClientReceived:
break;
case CommHelpers.CommType.ServerToClientFinished:
string ClientID = header.ClientID;
ConcurrentQueue<DataAndHeader> queueResultsForClient = null;
if (!dicResults.TryGetValue(ClientID, out queueResultsForClient))
{
queueResultsForClient = new ConcurrentQueue<DataAndHeader>();
if (!dicResults.TryAdd(ClientID, queueResultsForClient))
{
}
}
queueResultsForClient.Enqueue(dat);
break;
}
}
[HttpGet]
// [Route("download")]
public byte[] download(string ClientID)
{
// some logic
return new byte[0];
}
}
}
I want to wait till i get the Response from the External Server and loaded into my Controller after that i want to enable the button. After the button is enabled and clicked by Client he should be able to download file.
The "getdoc()" works only when i click download button. but initially the download button is in disable state. I want to programatically enable it from my controller not from my Client
Thanks in Advance.
Try the following code:
getdoc() {
this.download.downloadDoc()
.subscribe(res => {
this.datadownload = new Blob([res], { type: 'application/txt' });
saveAs(this.datadownload);
console.log(this.datadownload);
this.disabled = false; // This is the change
}, error => {
this.disabled = true;
console.log('error while downloading', error)
})
}

How to wait and get return value from ViewModel using Caliburn Micro ActivateItem

I'm developing a desktop application that can communicate with a browser. What I want is to send a parameter from the browser to the desktop app to do some process and then get the return value as value.
In the app, I use Nancy to get POST data from the browser. Then I pass the data to SignHashViewModel as parameter to do some process, but I can't get the value from SignHashViewModel.
I'm trying to learn async and await to see if that can solve the problem, but I don't know how to apply it to my code.
Javascript code below posts a string hash to the Nancy server and gets the result back:
Signhash.php
<?php
if (isset($_GET['hashStr']))
{
$hashStr = $_GET['hashStr']; // get param from URL
}
?>
<script type="text/javascript">
$(document).ready(function() {
var hash = JSON.stringify("<?php echo $hashStr ?>");
$.post("http://localhost:50011/MyProject/signHash", {hash}, function(data) //this line will post hash to nancy server and get the data as result
{
var result = JSON.parse(data);
console.log("ErrCode : " + result.ErrCode );
console.log("ErrMsg : " + result.ErrMsg );
console.log("CertData : " + result.CertData );
});
});
</script>
to get POST data from the javascript i used this class.
ServerModule.cs
Post ("/signHash", (args) =>
{
string result = null;
List<string> dataItem= new List<string>();
ActivateItems.OpenItem(new SignHashViewModel(dataItem)); //This line activate the screen with param
return result; // Here I dont know how to get return value from SignHashViewModel
});
This class will sign a hash
SignHashViewModel.cs
public SignHashViewModel(List<string> dataItem)
{
DataItem = dataItem; // Set as Property
}
public PDFInfo Sign() //Run this method when button is clicked
{
PDFInfo pi = new PDFInfo();
SignHashToken jsonData = new SignHashToken();
pi = jsonData.SignHash(DataItem , userPin); //
return result;
}
I expected that I could get the result of SignHashViewModel and pass to the browser. Hope someone could help me on this or providing any other solution would be great too, thank you.

Lambda Function using c# cannot invoke external HTTPS APIs

I am trying to invoke External APIs from AWS lambda function written in c#. The Lamda function is deployed in No VPC mode. I am calling this function from Alexa skill. The code works fine for an http request, but its not working for https.
The below code works when I use http://www.google.com.
But, if I replace http with https, then I get the error in the cloud watch saying:
"Process exited before completing request."
Even the log written in catch is not getting logged in cloud watch.
public class Function
{
public const string INVOCATION_NAME = "bingo";
public async Task<SkillResponse> FunctionHandler(SkillRequest input, ILambdaContext context)
{
var requestType = input.GetRequestType();
if (requestType == typeof(IntentRequest))
{
string response = "";
IntentRequest request = input.Request as IntentRequest;
response += $"About {request.Intent.Slots["carmodel"].Value}";
try
{
using (var httpClient = new HttpClient())
{
Console.WriteLine("Trying to access internet");
//var resp=httpClient.GetAsync("http://www.google.com").Result // this works perfect!
var resp = httpClient.GetAsync("https://www.google.com").Result; // this throws error
Console.WriteLine("Call was successful");
}
}
catch (Exception ex)
{
Console.WriteLine("Exception from main function " + ex.Message);
Console.WriteLine(ex.InnerException.Message);
Console.WriteLine(ex.StackTrace);
}
return MakeSkillResponse(response, true);
}
else
{
return MakeSkillResponse(
$"I don't know how to handle this intent. Please say something like Alexa, ask {INVOCATION_NAME} about Tesla.",
true);
}
}
private SkillResponse MakeSkillResponse(string outputSpeech, bool shouldEndSession,
string repromptText = "Just say, tell me about car models to learn more. To exit, say, exit.")
{
var response = new ResponseBody
{
ShouldEndSession = shouldEndSession,
OutputSpeech = new PlainTextOutputSpeech { Text = outputSpeech }
};
if (repromptText != null)
{
response.Reprompt = new Reprompt() { OutputSpeech = new PlainTextOutputSpeech() { Text = repromptText } };
}
var skillResponse = new SkillResponse
{
Response = response,
Version = "1.0"
};
return skillResponse;
}
}
The issue was resolved by updating the library version.
System.Net.Http v4.3.4 was not completely compatible with dotnet core v1.
So outbound http calls were working but not https calls. Changing the version of System.net.http resolved the issue.

Best practice for interpreting MVC errors in Angular 2

I have a MVC 5 backend written in C#. It serves MVC views written in Razor and also some Angular 2 pages.
What is the best way to handle potential errors when calling server from client? I really would like to establish a pattern that is robust and works in all situations. Below is what I have tried so far.
Backend C# code:
public class MyController : Controller
{
[HttpGet]
public ActionResult GetUsers()
{
try
{
// Lot of fancy server code ...
throw new Exception("Dummy error");
return GetCompressedResult(json);
}
catch (Exception ex)
{
throw new HttpException(501, ex.Message);
}
}
private FileContentResult GetCompressedResult(string json)
{
// Transform to byte array
var bytes = Encoding.UTF8.GetBytes(json);
// Compress array
var compressedBytes = bytes.Compress();
HttpContext.Response.AppendHeader("Content-encoding", "gzip");
return new FileContentResult(compressedBytes, "application/json");
}
}
Client side Angular 2 code:
public loadDataFromServer() {
let response = this.http.get(this.urlGetData)
.map((res: Response) => res.json())
.catch(this.handleError);
response.subscribe(response => {
// Process valid result ...
},
err => { console.error(err); }
);
};
private handleError(error: Response | any) {
let errMsg: string;
if (error instanceof Response) {
const body = JSON.parse(JSON.stringify(error || null))
const err = body.error || JSON.stringify(body);
errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
} else {
errMsg = error.message ? error.message : error.toString();
}
console.error(errMsg);
return Observable.throw(errMsg);
}
This is a printscreen of the error object processed by handleError method:
This all raises some questions:
Is it correct to throw custom HttpException from server?
Is handleError method correct or maybe too complex?
On client side I would like to see the custom error message, but currently it is just found in an enormous "blob" of HTML that is nasty to parse.
Is client side error handling necessary BOTH in get call and subscribe action?
My current suggestion is to let server respond with Json object for all handled exceptions.
On client side I check result object for possible error property before handling valid result.
The handleResponseError method will parse typed Response object and throw observable message. But at least my browser (Chrome 57) seems to automatically log response errors to console. So if subscriber need no specific extra handling for different errors, then the subscriber need no extra action for err object.
Please feedback if there are better ways!
Backend C# code:
public class MyController : Controller
{
[HttpGet]
public ActionResult GetUsers()
{
try
{
// Lot of fancy server code ...
throw new ArgumentException("Dummy error");
// Normal return of result ...
}
catch (Exception ex)
{
return Json(new { error = $"{ex.GetType().FullName}: '{ex.Message}'" }, JsonRequestBehavior.AllowGet);
}
}
}
Client side Angular 2 code:
public loadDataFromServer() {
let response = this.http.get(this.urlGetData)
.map((res: Response) => res.json())
.catch(this.handleResponseError);
response.subscribe(result => {
if (result.error) {
this.displayJsonError(this.urlGetUsers, result.error);
}
else {
// Process valid result
}
});
};
private handleResponseError(value: Response | any) {
let errorMessage = value.toString();
let response = value as Response;
if (response) {
errorMessage = `${response.status}: ${response.statusText}\n${response.toString()}`;
}
if (value.error) {
errorMessage = value.error;
}
if (value.message) {
errorMessage = value.message;
}
return Observable.throw(errorMessage);
}
private displayJsonError(url: string, error: string) {
console.error(`Call to '${url}' failed with ${error}`);
}

Categories

Resources